最近因為項目的原因需要實現一個來電監聽,且產生一個懸浮視窗提示相關資訊(具體什麼資訊不方便透露哈)。
現把我的思路及實現方法大致說下哈。
想要監聽來電首先需要要manifest中申明"android.permission.READ_PHONE_STATE"許可權
Xml代碼
- <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
還需要註冊來電監聽,目前我的處理方式是接收開機廣播,然後在接收到廣播後註冊來電監聽。接收開機廣播需要有“android.permission.RECEIVE_BOOT_COMPLETED”許可權,manifest中申明如下
Java代碼
- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
然後註冊廣播接收類
Xml代碼
- <receiver android:name=".PhoneBootReceiver">
- <intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED" />
- </intent-filter>
- </receiver>
<receiver android:name=".PhoneBootReceiver"><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED" /></intent-filter></receiver>
PhoneBootReceiver中註冊監聽來電,首先得擷取系統服務“TELEPHONY_SERVICE”
Java代碼
- TelephonyManager telM = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
TelephonyManager telM = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
然後添加監聽
Java代碼
- telM.listen(new TelListener(context), PhoneStateListener.LISTEN_CALL_STATE);
telM.listen(new TelListener(context), PhoneStateListener.LISTEN_CALL_STATE);
TelListener是自己定義的電話狀態監聽類,繼承自PhoneStateListener,監聽來電只需要實現onCallStateChanged(int state, String incomingNumber)方法。
咳咳...標題上說了彈出懸浮視窗,其實懸浮視窗就是在WindowManager中添加一個View,這個功能我也是在TelListener實現的。要想實現懸浮視窗,首先得有“android.permission.SYSTEM_ALERT_WINDOW”的許可權,在manifest中申明如下:
Xml代碼
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
WindowManager需要通過context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
來擷取。
先把TelListener源碼放出來,再詳解
Xml代碼
- public class TelListener extends PhoneStateListener {
-
-
- private Context context;
- private WindowManager wm;
- private TextView tv;
- public TelListener(Context context){
- this.context = context;
- }
-
- @Override
- public void onCallStateChanged(int state, String incomingNumber) {
- // TODO Auto-generated method stub
- super.onCallStateChanged(state, incomingNumber);
- if(state == TelephonyManager.CALL_STATE_RINGING){
-
- wm = (WindowManager)context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
- WindowManager.LayoutParams params = new WindowManager.LayoutParams();
- params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
- params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-
- params.width = WindowManager.LayoutParams.WRAP_CONTENT;
- params.height = WindowManager.LayoutParams.WRAP_CONTENT;
- <SPAN style="WHITE-SPACE: pre"> </SPAN>params.format = PixelFormat.RGBA_8888;
- tv = new TextView(context);
- tv.setText("這是懸浮視窗,來電號碼:" + incomingNumber);
- wm.addView(tv, params);
-
- }else if(state == TelephonyManager.CALL_STATE_IDLE){
- if(wm != null){
- wm.removeView(tv);
- }
- }
- }
- }
public class TelListener extends PhoneStateListener {private Context context;private WindowManager wm;private TextView tv;public TelListener(Context context){this.context = context;}@Overridepublic void onCallStateChanged(int state, String incomingNumber) {// TODO Auto-generated method stubsuper.onCallStateChanged(state, incomingNumber);if(state == TelephonyManager.CALL_STATE_RINGING){wm = (WindowManager)context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE); WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.format = PixelFormat.RGBA_8888;tv = new TextView(context); tv.setText("這是懸浮視窗,來電號碼:" + incomingNumber);wm.addView(tv, params);}else if(state == TelephonyManager.CALL_STATE_IDLE){if(wm != null){wm.removeView(tv);}}}}
state = TelephonyManager.CALL_STATE_RINGING表示有新的來電,state = TelephonyManager.CALL_STATE_IDLE表示電話中斷(可能理解不是很準確,電話掛斷的時候state會和TelephonyManager.CALL_STATE_IDLE相等)
定義視窗布局
Java代碼
- WindowManager.LayoutParams params = new WindowManager.LayoutParams();
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
設定視窗類別型在所有視窗之上
Java代碼
- params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
別忘了
Java代碼
- params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
如果沒有這句話的話,在產生懸浮視窗後,懸浮視窗後的介面上東西都不能點。這句話的目的是讓懸浮視窗失去焦點。
背景透明
Java代碼
- params.format = PixelFormat.RGBA_8888;
params.format = PixelFormat.RGBA_8888;
本例中懸浮視窗只是顯示一個TextView其內容為“這是懸浮視窗,來電號碼:xxxxxx”,最後將TextView添加到表單中
Java代碼
- wm.addView(tv, params);
wm.addView(tv, params);
在電話中斷後將TextView移除,否則會一直顯示的...
Java代碼
- wm.removeView(tv);
wm.removeView(tv);
啦..本文就到這兒了...
“啥?要可移動的?”
要想可以拖動的話,那給TextView添加setOnTouchListener,實現OnTouchListener的onTouchListener方法。
對了,別忘了將
Java代碼
- params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
修改為
Java代碼
- params.type = WindowManager.LayoutParams.TYPE_PHONE;
params.type = WindowManager.LayoutParams.TYPE_PHONE;
因為TYPE_SYSTEM_OVERLAY的話是TextView擷取不到輸入焦點,也就沒法拖動了哈。