一 監聽手機Phone狀態
在手機里面監聽Phone的狀態有兩種方法:
1 注冊接收廣播
AndroidMenifest.xml: <receiver android:name="CallListener" > <intent-filter> <action android:name="android.intent.action.PHONE_STATE" /> <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> </intent-filter> </receiver> 權限 <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 廣播: public class CallListener extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent){ } }
2 注冊PhoneStateListener
//獲得相應的系統服務
TelephonyManager tm = (TelephonyManager) getSystemService( Context.TELEPHONY_SERVICE);
//創建Listener
MyPhoneCallListener myPhoneCallListener = new MyPhoneCallListener(); //注冊監聽 設置監聽的State
tm.listen(myPhoneCallListener, PhoneStateListener.LISTEN_CALL_STATE); //實現PhoneStateListener listener並實現相應的方法
public class MyPhoneCallListener extends PhoneStateListener { @Override public void onCallStateChanged(int state, String incomingNumber) { switch (state) { //電話通話的狀態
case TelephonyManager.CALL_STATE_OFFHOOK: break; //電話響鈴的狀態
case TelephonyManager.CALL_STATE_RINGING: break; //空閑中
case TelephonyManager.CALL_STATE_IDLE: break; } super.onCallStateChanged(state, incomingNumber); } }
這里需要通過TelephonyManager,那么注冊過程是如果實現的,以及觸發的過程又是如何的呢。
Framework層telephony處理的核心是RIL這個類,網絡層得各種狀態變化由此傳遞給監聽者。
Application層很多的地方都需要對Phone的state進行監聽處理。下面將此過程是如何實現的。
類繼承結構圖:
二 監聽Phone狀態的實現機制
Phone state listen 時序圖:
1 PhoneNotifier與Phone
在PhoneFactory中對Framework的telephony層進行了對象的初始化:
public static void makeDefaultPhone(Context context) { sPhoneNotifier = new DefaultPhoneNotifier(); //創建CommandsInterface實例
sCommandsInterface = new RIL(context, networkMode, cdmaSubscription); //創建Phone實例 以及代理對象ProxyPhone
sProxyPhone = new PhoneProxy(new GSMPhone(context, sCommandsInterface, sPhoneNotifier)); } Public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) { // notifier
super(notifier, context, ci, unitTestMode); }
在創建GSMPhone父類時傳遞了PhoneNotifier對象到PhoneBase類中:
protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci, boolean unitTestMode) { //保存notifier對象引用
this.mNotifier = notifier; this.mContext = context; mLooper = Looper.myLooper(); mCM = ci; //PhoneBase是個handler 注冊來電監聽
mCM.setOnCallRing(this, EVENT_CALL_RING, null); }
這里看到:GSMPhone將存儲了一個PhoneNotifier對象的引用,PhoneBase是一個Handler,
但是並沒有注冊到RIL 的mCallStateRegistrants表中對Phone狀態變化的事件監聽,也沒有在PhoneBase中
看到使用mNotifier來進行PhoneStateListener .LISTEN_CALL_STATE狀態的通知觸發。
其實通過代碼可以看到Phone的狀態並不是直接由RIL來控制判斷的,而是類GsmCallTracker對各種狀態監聽,綜合起來進行判斷通知的。
簡單看下這個類繼承結構:
這個類也挺復雜,先看看這樣一個函數:
GsmCallTracker:
private void updatePhoneState() { Phone.State oldState = state; //判斷狀態有無變化
…… if (state != oldState) { //GSMPhone
phone.notifyPhoneStateChanged(); } }
GSMPhone:
void notifyPhoneStateChanged() { //這就是在創建GSMPhone時傳遞的PhoneNotifier——DefaultPhoneNotifier
mNotifier.notifyPhoneState(this); }
從這里就到了PhoneNotifier派生類DefaultPhoneNotifier中,將狀態變化通知其注冊監聽者。
DefaultPhoneNotifier:
public void notifyPhoneState(Phone sender) { Call ringingCall = sender.getRingingCall(); String incomingNumber = ""; if (ringingCall != null && ringingCall.getEarliestConnection() != null){ incomingNumber = ringingCall.getEarliestConnection().getAddress(); } try { //remote調用,通知Call State
mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber); } catch (RemoteException ex) { // system process is dead
} }
對狀態的監聽注冊Listener ,都是在TelephonyRegistry中進行。
2 TelephonyRegistry和PhoneStateListener
看一下PhoneNotifier相關類繼承結構:
ServiceManager.addService("telephony.registry", new TelephonyRegistry(context));
這里核心的類就是TelephonyRegistry,從ITelephonyRegistry.Stub繼承下來,這個類是運行在SystemServer中,
作為Framework層Service,可以通過binder進程間通信,提供了狀態的注冊監聽,狀態變化的通知。
在上面監聽Phone狀態的一種方式里面,通過繼承PhoneStateListener來實現;繼承結構中有個IPhoneStateListener這是AIDL文件所自動生成的類。
AIDL文件是按照已搭建好的框架,自動生成進程間通信所需要的接口和類,自動生成的類繼承結構關系都如下:
再看一下實現監聽需要重寫的類PhoneStateListener:
PhoneStateListener持有了IPhoneStateListener.Stub對象callback,因為我們想要實現監聽Phone狀態的所在進程和
通知phone狀態變化的進程,不是同一個進程中,要實現跨進程的通信,需要使用Binder實現。
所以在注冊到TelephonyRegistry服務中的listener是一個IPhoneStateListener.Stub的binder對象。
3 Phone狀態監聽注冊
注冊過程:
//獲得相應的系統服務 TelephonyManager tm = (TelephonyManager) getSystemService( Context.TELEPHONY_SERVICE); //創建Listener MyPhoneCallListener myPhoneCallListener = new MyPhoneCallListener(); //注冊監聽 設置監聽的State tm.listen(myPhoneCallListener, PhoneStateListener.LISTEN_CALL_STATE);
獲取系統服務是運行在在當前進程中的:ContextImpl.java
registerService(TELEPHONY_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new TelephonyManager(ctx.getOuterContext()); }}); //TelephonyManager遠程代理服務對象TelephonyRegistry:
public void listen(PhoneStateListener listener, int events) { //注冊監聽對象
sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow); }
TelephonyManager遠程代理服務對象TelephonyRegistry:
注冊對象是在服務TelephonyRegistry中完成:
public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow) { synchronized (mRecords) { // register
Record r = null; find_and_add: { IBinder b = callback.asBinder(); final int N = mRecords.size(); for (int i = 0; i < N; i++) { r = mRecords.get(i); if (b == r.binder) { break find_and_add; } } // ArrayList< Record >
r = new Record(); r.binder = b; r.callback = callback; r.pkgForDebug = pkgForDebug; mRecords.add(r); } }
4 觸發通知狀態變化
public void notifyPhoneState(Phone sender) { //remote對象TelephonyRegistry
mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber); }
TelephonyRegistry服務觸發狀態變化通知:
public void notifyCallState(int state, String incomingNumber) { synchronized (mRecords) { mCallState = state; mCallIncomingNumber = incomingNumber; for (Record r : mRecords) { if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) { // remote對象回調
r.callback.onCallStateChanged(state, incomingNumber); } } } //發送廣播
broadcastCallStateChanged(state, incomingNumber); }
這里看到通過兩種方式通知Phone狀態有變化:接口回調和發送廣播
接口回調:PhoneStateListener中的IPhoneStateListener實例callback
IPhoneStateListener callback = new IPhoneStateListener.Stub() { public void onCallStateChanged(int state, String incomingNumber) { //Handler發送消息異步處理 Message.obtain(mHandler, LISTEN_CALL_STATE, state, 0, incomingNumber).sendToTarget(); } } Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case LISTEN_CALL_STATE: //調用子類MyPhoneCallListener接口 PhoneStateListener.this.onCallStateChanged(msg.arg1, (String)msg.obj); break; } } }
發送廣播:
private void broadcastCallStateChanged(int state, String incomingNumber) { //ACTION:android.intent.action.PHONE_STATE 正是廣播所監聽的ACTION
Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED); intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertCallState(state). toString()); if (!TextUtils.isEmpty(incomingNumber)) { intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber); } mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE); }