1.主activity
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.ypy.eventbus.EventBus;
import eventbus.FristEvent;
import flow.FloatingWindowService;
public class MainActivity extends Activity {
private boolean flag =false;// 标识符:用来标志悬浮窗是不是出现过,
PhoneCallStateService service;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册EventBus
EventBus.getDefault().register(this);
service = new PhoneCallStateService();
Intent intent = new Intent(this,PhoneCallStateService.class);
startService(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
//反注册
EventBus.getDefault().unregister(this);
}
public void onEventMainThread(FristEvent event){
//如果是来电状态,显示浮窗
if ((event.getMsg()).equals("in")){
flag = true;
Intent show = new Intent(this, FloatingWindowService.class);
show.putExtra(FloatingWindowService.OPERATION, FloatingWindowService.OPERATION_SHOW);
startService(show);
}
//如果是空闲状态,隐藏浮窗
if(event.getMsg().equals("free")&&flag == true){
flag =false;
Intent hide = new Intent(this, FloatingWindowService.class);
hide.putExtra(FloatingWindowService.OPERATION, FloatingWindowService.OPERATION_HIDE);
startService(hide);
}
}
}
2.录音机
import android.media.MediaRecorder;
import android.os.Environment;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by Administrator on 2016/7/25.
* 录音机
*/
public class MyRecorder {
private String phoneNumber;
private MediaRecorder recorder;
private boolean started = false; //录音机是否已经启动
private boolean isCommingNumber = false;//是否是来电
private String TAG = "Recorder";
public MyRecorder(String phoneNumber) {
this.setPhoneNumber(phoneNumber);
}
public MyRecorder() {
}
public void start() {
started = true;
recorder = new MediaRecorder();
File recordPath = new File(
Environment.getExternalStorageDirectory()
, "/My record");
if (!recordPath.exists()) {
recordPath.mkdirs();
Log.d("recorder", "创建目录");
}
String callDir = "通话录音";
if (isCommingNumber) {
callDir = "呼入";
}
String fileName = callDir + "-" + phoneNumber + "-"
+ new SimpleDateFormat("yy-MM-dd_HH-mm-ss")
.format(new Date(System.currentTimeMillis())) + ".mp3";//实际是3gp
File recordName = new File(recordPath, fileName);
try {
recordName.createNewFile();
Log.d("recorder", "创建文件" + recordName.getName());
} catch (IOException e) {
e.printStackTrace();
}
recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);//从麦克风采集声音
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); //内容输出格式
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);//音频编码方式
recorder.setOutputFile(recordName.getAbsolutePath());
try {
recorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
recorder.start();
started = true;
Log.d(TAG, "录音开始");
}
public void stop() {
try {
if (recorder != null) {
recorder.stop();
recorder.release();
recorder = null;
}
started = false;
} catch (IllegalStateException e) {
e.printStackTrace();
}
Log.d(TAG, "录音结束");
}
public void pause() {
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public boolean isStarted() {
return started;
}
public void setStarted(boolean hasStarted) {
this.started = hasStarted;
}
public boolean isCommingNumber() {
return isCommingNumber;
}
public void setIsCommingNumber(boolean isCommingNumber) {
this.isCommingNumber = isCommingNumber;
}
}
3.广播监听
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
/**
* Created by Administrator on 2016/7/25.
*
* 广播接受者,初测广播后来接受广播的消息
*/
public class OutgoingCallReciver extends BroadcastReceiver {
static final String TAG = "Recorder";
private MyRecorder recorder;
public OutgoingCallReciver() {
recorder = new MyRecorder();
}
public OutgoingCallReciver (MyRecorder recorder) {
this.recorder = recorder;
}
@Override
public void onReceive(Context ctx, Intent intent) {
String phoneState = intent.getAction();
Log.d(TAG, "广播接收者的Action:"+phoneState);
if (phoneState.equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
String phoneNum = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);//拨出号码
recorder.setPhoneNumber(phoneNum);
recorder.setIsCommingNumber(false);
Log.d(TAG, "设置为去电状态");
Log.d(TAG, "去电状态 呼叫:" + phoneNum);
}
if (phoneState.equals(OutgoingCallState.ForeGroundCallState.DIALING)) {
Log.d(TAG, "正在拨号...");
}
if (phoneState.equals(OutgoingCallState.ForeGroundCallState.ALERTING)) {
Log.d(TAG, "正在呼叫...");
}
if (phoneState.equals(OutgoingCallState.ForeGroundCallState.ACTIVE)) {
if (!recorder.isCommingNumber() && !recorder.isStarted()) {
Log.d(TAG, "去电已接通 启动录音机");
recorder.start();
}
}
if (phoneState.equals(OutgoingCallState.ForeGroundCallState.DISCONNECTED)) {
if (!recorder.isCommingNumber() && recorder.isStarted()) {
Log.d(TAG, "已挂断 关闭录音机");
recorder.stop();
}
}
}
}
4.电话监听服务
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
import listener.TelListener;
/**
* Created by Administrator on 2016/7/25.
* 创建服务来进行监听
*
*/
public class PhoneCallStateService extends Service {
private OutgoingCallState outgoingCallState;
private OutgoingCallReciver outgoingCallReciver;
private MyRecorder recorder;
@Override
public void onCreate() {
super.onCreate();
//------以下应放在onStartCommand中,但2.3.5以下版本不会因service重新启动而重新调用--------
//监听电话状态,如果是打入且接听 或者 打出 则开始自动录音
//通话结束,保存文件到外部存储器上
recorder = new MyRecorder();
outgoingCallReciver = new OutgoingCallReciver(recorder);
Toast.makeText(this, "服务已启动", Toast.LENGTH_LONG).show();
//去电
IntentFilter outgoingCallFilter = new IntentFilter();
outgoingCallFilter.addAction("android.intent.action.PHONE_STATE");
//注册接收者
registerReceiver(outgoingCallReciver, outgoingCallFilter);
//来电
TelephonyManager telmgr = (TelephonyManager)getSystemService(
Context.TELEPHONY_SERVICE);
telmgr.listen(new TelListener(recorder), PhoneStateListener.LISTEN_CALL_STATE);
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(outgoingCallReciver);
Toast.makeText(
this, "已关闭电话监听服务", Toast.LENGTH_LONG)
.show();
Log.d("Recorder", "已关闭电话监听服务");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
}
5.eventbus实体类
/**
* Created by Administrator on 2016/7/26.
*/
public class FristEvent {
private String msg;
public FristEvent(String msg){
this.msg = msg;
}
public String getMsg(){
return this.msg;
}
}
6.悬浮窗
import java.util.ArrayList;
import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.Button;
public class FloatingWindowService extends Service {
public static final String OPERATION = "operation";
public static final int OPERATION_SHOW = 100;
public static final int OPERATION_HIDE = 101;
private static final int HANDLE_CHECK_ACTIVITY = 200;
public boolean isAdded = false; // 是否已增加悬浮窗
private static WindowManager wm;
private static WindowManager.LayoutParams params;
private Button btn_floatView;
private List<String> homeList; // 桌面应用程序包名列表
private ActivityManager mActivityManager;
int operation;
// private boolean flag;//判断
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
homeList = getHomes();
createFloatView();
}
@Override
public void onDestroy() {
super.onDestroy();
}
/**
* 在Service里的onStart方法中,只需要根据传过来的操作参数,对handler检查进行操作即可
* */
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
operation = intent.getIntExtra(OPERATION, -1);
switch(operation) {
case OPERATION_SHOW:
mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);
mHandler.sendEmptyMessage(HANDLE_CHECK_ACTIVITY);
break;
case OPERATION_HIDE:
mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);
mHandler.sendEmptyMessage(HANDLE_CHECK_ACTIVITY);
break;
}
}
/**
* 创建悬浮窗
*/
private void createFloatView() {
btn_floatView = new Button(getApplicationContext());
btn_floatView.setText("悬浮窗");
wm = (WindowManager) getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE);
params = new WindowManager.LayoutParams();
// 设置window type
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
/*
* 如果设置为params.type = WindowManager.LayoutParams.TYPE_PHONE;
* 那么优先级会降低一些, 即拉下通知栏不可见
*/
params.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明
params.alpha=100;
// 设置Window flag
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
/*
* 下面的flags属性的效果形同“锁定”。
* 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。
wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE
| LayoutParams.FLAG_NOT_TOUCHABLE;
*/
// 设置悬浮窗的长得宽
// LinearLayout.LayoutParams params=new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
// 设置悬浮窗的Touch监听
btn_floatView.setOnTouchListener(new OnTouchListener() {
int lastX, lastY;
int paramX, paramY;
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
paramX = params.x;
paramY = params.y;
break;
case MotionEvent.ACTION_MOVE:
int dx = (int) event.getRawX() - lastX;
int dy = (int) event.getRawY() - lastY;
params.x = paramX + dx;
params.y = paramY + dy;
// 更新悬浮窗位置
wm.updateViewLayout(btn_floatView, params);
break;
}
return true;
}
});
wm.addView(btn_floatView, params);
isAdded = true;
Log.i("悬浮窗中背景颜色是否为透明","颜色值:"+params.format);
}
/**
*
* 首先需要先获取到手机上的桌面程序的包名(桌面程序指的是按下HOME键所列出的程序,如go桌面等):
* 获得属于桌面的应用的应用包名称
* @return 返回包含所有包名的字符串列表
*/
private List<String> getHomes() {
List<String> names = new ArrayList<String>();
PackageManager packageManager = this.getPackageManager();
// 属性
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
for(ResolveInfo ri : resolveInfo) {
names.add(ri.activityInfo.packageName);
}
return names;
}
/**
*
* 接着是判断当前运行的Activity是否为桌面应用程序,这里需要用到ActivityManager
* 判断当前界面是否是桌面
*/
public boolean isHome(){
if(mActivityManager == null) {
mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
}
List<RunningTaskInfo> rti = mActivityManager.getRunningTasks(1);
return homeList.contains(rti.get(0).topActivity.getPackageName());
}
/**
*
*有了上面两个方法,就可以实现这个功能了。只不过我们需要定时去判断,例如可以用一个Handler每一秒去检查一次:
*/
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case HANDLE_CHECK_ACTIVITY:
if(isHome()) {
if (!isAdded&&operation==100) {
wm.addView(btn_floatView, params);
isAdded = true;
}
else if (isAdded&&operation==101){
wm.removeView(btn_floatView);
isAdded = false;
}
} else {
if(isAdded) {
wm.removeView(btn_floatView);
isAdded = false;
}
}
mHandler.sendEmptyMessageDelayed(HANDLE_CHECK_ACTIVITY, 1000);
break;
}
}
};
}
7.监听服务
import android.content.Context;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import com.ypy.eventbus.EventBus;
import boeryun.zlcloud.com.soundrecording.MyRecorder;
import eventbus.FristEvent;
/**
* Created by Administrator on 2016/7/25.
*
*/
public class TelListener extends PhoneStateListener {
private MyRecorder myRecorder = new MyRecorder();
public TelListener(MyRecorder recorder) {
this.myRecorder = recorder;
}
private boolean flag=false;//判断录音机是否打开
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE: // 空闲状态,即无来电也无去电
Log.i("TelephoneState", "IDLE");
//此处添加一系列功能代
if(flag){
flag =false;
myRecorder.stop();
}
EventBus.getDefault().post(new FristEvent("free"));
break;
case TelephonyManager.CALL_STATE_RINGING: // 来电响铃
Log.i("TelephoneState", "RINGING");
//此处添加一系列功能代码
EventBus.getDefault().post(new FristEvent("in"));
break;
case TelephonyManager.CALL_STATE_OFFHOOK: // 摘机,即接通
Log.i("TelephoneState", "OFFHOOK");
//此处添加一系列功能代码
flag = true;
myRecorder.start();
break;
}
Log.i("TelephoneState", String.valueOf(incomingNumber));
}
}
8.一系列权限
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="boeryun.zlcloud.com.soundrecording" >
<!-- 录音监听胡权限-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<!-- 录音功能权限-->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!--系统读取日志的权限-->
<uses-permission android:name="android.permission.READ_LOGS"/>
<!-- 允许程序访问外部存储设备 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 允许创建和删除外部存储设备的文件 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 悬浮窗权限-->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 注册服务 -->
<service android:name="boeryun.zlcloud.com.soundrecording.PhoneCallStateService"
android:enabled="true"
android:exported="true"/>
<service android:name="flow.FloatingWindowService"
/>
</application>
</manifest>