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>