Phone狀態的監聽機制


一 監聽手機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狀態的實現機制

[原創]Android Telephony 分析[PART IV] - 〇〇柒 - 朝陽光出發

 

 

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); }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM