Android 耳機事件傳遞流程

原文鏈接:https://blog.csdn.net/frakie_kwok/article/details/73729804

感謝作者分享,轉載僅供備忘。

在項目中,遇到問題:插入不帶麥耳機,狀態欄顯示仍然是帶麥圖標。 
解決此問題涉及到耳機的拔插事件傳遞流程,在此分析一下Android系統,耳機拔插流程源碼分析。

Android系統的耳機目前可以實現拍照、暫停/播放、打電話等功能,這一切的基礎是耳機拔插成功,結合InputManagerService的相關知識,主要從framework層面分析耳機插拔事件的傳遞。

一、驅動層的事件上傳

使用adb 命令可以查看當前手機插入的耳機狀態,命令爲:adb shell cat /sys/class/switch/h2w/state

  • 插入帶麥耳機

ubuntu@ubuntu:~/headset$ adb shell cat /sys/class/switch/h2w/state 
11

  • 插入不帶麥耳機

ubuntu@ubuntu:~/headset$ adb shell cat /sys/class/switch/h2w/state 
9

通過這個命令,我們可以初步判斷,狀態欄耳機顯示異常問題是出現在驅動層還是上層。

二、framework層代碼分析

前文提到,耳機拔插主要涉及到InputManagerService這個系統重量級服務。關於IMS(inoutManagerService)的具體介紹,請參考此文章:http://blog.csdn.net/jinzhuojun/article/details/41909159 ,作者很詳盡的介紹了IPM的事件讀取和分發過程。 本文章只挑揀IPM中與耳機事件相關的內容分析。 
Android系統的事件主要分爲兩類:

  • 按鍵事件(KeyEvent) 
    由物理按鍵產生的事件。 對於嵌入式設備,通常不會保留太多的物理按鍵,手機一般有Home, Back, Menu, Volume Down, Volume Up,我們討論的耳機事件也歸類在此。

  • 觸摸事件(TouchEvent) 
    在手機屏幕上面的點擊、拖動事件,以及它們的組合產生的各種事件。

2.1 涉及到的類

InputManagerService.java 
/framework/base/services/core/java/com/android/server/input/InputManagerService.java

WiredAccessoryManager.java 
/framework/base/services/core/java/com/android/server/WiredAccessoryManager.java

config.xml 
/framework/base/core/res/res/values/config.xml

SystemServer.java 
/framework/base/services/java/com/android/server/SystemServer.java

AudioManager.java 
/framework/base/media/java/android/media/AudioManager.java

AudioService.java 
framework/base/media/java/android/media/AudioService.java

2.2 設置Event上傳方式 
Android中有兩種Event上傳方式:InputEvent(linux的 /dev/input/event subsystem),和UEvent(framework下的比較老的event方式),兩種方式的切換是通過屬性配置實現的,在config.xml文件中,有如下代碼:

<!-- When true use the linux /dev/input/event subsystem to detect the switch changes on the headphone/microphone jack. 
When false use the older uevent framework. -->
<bool name="config_useDevInputEventForAudioJack">false</bool>
  • 1
  • 2
  • 3
    public InputManagerService(Context context) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

        String doubleTouchGestureEnablePath = context.getResources().getString(
                R.string.config_doubleTouchGestureEnableFile);
        mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
            new File(doubleTouchGestureEnablePath);

        LocalServices.addService(InputManagerInternal.class, new LocalService());
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

useDevInputEventForAudioJack設置爲true使用/dev/input/event,FALSE時設置爲UEvent. 
在這裏我們可以看到,當前使用的是UEvent方式。(UEvent方式支持熱插拔,是一種適合耳機拔插事件的方式。)

2.2 IMS 耳機事件傳遞 
插入耳機後,驅動層會將耳機事件首先,傳遞到IMS的notifySwitch()函數,驅動層的檢測與向上傳遞在此分析。

@2.2.1 notifySwitch()

    // Native callback.
    private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
        if (DEBUG) {
            Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
                    + ", mask=" + Integer.toHexString(switchMask));
        }
.....
.....

//此處是最重要的內容,在這裏,會將耳機拔插時間傳遞給mWiredAccessoryCallbacks回調
        if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
            mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
                    switchMask);
        }
......
......
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

@2.2.2 mWiredAccessoryCallbacks 的創建 
從上述代碼中,可以看出來,耳機事件被傳遞到了mWiredAccessoryCallbacks這個回調中。WiredAccessoryCallbacks這個回調就定義在IMS.java中,可以看到如下代碼:

    /**
     * Callback interface implemented by WiredAccessoryObserver.
     */
    public interface WiredAccessoryCallbacks {
        public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
        public void systemReady();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

這個回調的初始化在setWiredAccessoryCallbacks()函數實現

   public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
        mWiredAccessoryCallbacks = callbacks;
    }
  • 1
  • 2
  • 3

setWiredAccessoryCallbacks()函數是在IMS在初始化的時候調用的,也就是在SystemServer.java中被調用的。 
IMS被歸類在其他服務中,啓動是在startOtherService()函數中,代碼如下:

traceBeginAndSlog("StartWiredAccessoryManager");
            try {
                // Listen for wired headset changes
                inputManager.setWiredAccessoryCallbacks(
                        new WiredAccessoryManager(context, inputManager));
            } catch (Throwable e) {
                reportWtf("starting WiredAccessoryManager", e);
            }
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

可以看見,這裏將WiredAccessoryManager的實例傳遞給了mWiredAccessoryCallbacks ,所以,最終是WiredAccessoryManager在處理notifyWiredAccessoryChanged()方法。

@2.2.3 WiredAccessoryManager—notifyWiredAccessoryChanged

    @Override
    public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) {
        if (LOG) Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos
                + " bits=" + switchCodeToString(switchValues, switchMask)
                + " mask=" + Integer.toHexString(switchMask));

        synchronized (mLock) {
            int headset;
            mSwitchValues = (mSwitchValues & ~switchMask) | switchValues;
            switch (mSwitchValues &
                (SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT)) {
                case 0:
                    headset = 0;
                    break;
//不帶mic的耳機
                case SW_HEADPHONE_INSERT_BIT:
                    headset = BIT_HEADSET_NO_MIC;
                    break;

                case SW_LINEOUT_INSERT_BIT:
                    headset = BIT_LINEOUT;
                    break;

                case SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT:
                    headset = BIT_HEADSET;
                    break;
//帶mic的耳機
                case SW_MICROPHONE_INSERT_BIT:
                    headset = BIT_HEADSET;
                    break;

                default:
                    headset = 0;
                    break;
            }

            updateLocked(NAME_H2W,
                (mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) | headset);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

最終會跳到updateLocked方法,這個方法是用來檢查當前模式是否發生了變化,也就是耳機是否拔出、插入了(0->1 1->0)。

@2.2.4 WiredAccessoryManager—updateLocked()

    /**
     * Compare the existing headset state with the new state and pass along accordingly. Note
     * that this only supports a single headset at a time. Inserting both a usb and jacked headset
     * results in support for the last one plugged in. Similarly, unplugging either is seen as
     * unplugging all.
     *
     * @param newName One of the NAME_xxx variables defined above.
     * @param newState 0 or one of the BIT_xxx variables defined above.
     */
    private void updateLocked(String newName, int newState) {
        // Retain only relevant bits
        int headsetState = newState & SUPPORTED_HEADSETS;
        int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG;
        int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL;
        int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT);
        boolean h2wStateChange = true;
        boolean usbStateChange = true;
        if (LOG) Slog.v(TAG, "newName=" + newName
                + " newState=" + newState
                + " headsetState=" + headsetState
                + " prev headsetState=" + mHeadsetState);

        //add 
        mAudioManager.setNowPrevHeadsetState(headsetState,mHeadsetState);

        if (mHeadsetState == headsetState) {
            Log.e(TAG, "No state change.");
            return;
        }

        // reject all suspect transitions: only accept state changes from:
        // - a: 0 headset to 1 headset
        // - b: 1 headset to 0 headset
        if (h2w_headset == (BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) {
            Log.e(TAG, "Invalid combination, unsetting h2w flag");
            h2wStateChange = false;
        }
        // - c: 0 usb headset to 1 usb headset
        // - d: 1 usb headset to 0 usb headset
        if (usb_headset_anlg == BIT_USB_HEADSET_ANLG && usb_headset_dgtl == BIT_USB_HEADSET_DGTL) {
            Log.e(TAG, "Invalid combination, unsetting usb flag");
            usbStateChange = false;
        }
        if (!h2wStateChange && !usbStateChange) {
            Log.e(TAG, "invalid transition, returning ...");
            return;
        }

        mWakeLock.acquire();

        Log.i(TAG, "MSG_NEW_DEVICE_STATE");
        Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState,
                mHeadsetState, "");
        mHandler.sendMessage(msg);

        mHeadsetState = headsetState;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

@2.2.4 接下來交給mHandler

    private final Handler mHandler = new Handler(Looper.myLooper(), null, true) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_NEW_DEVICE_STATE:
                //將參數傳遞給setDevicesState()
                    setDevicesState(msg.arg1, msg.arg2, (String)msg.obj);
                    mWakeLock.release();
                    break;
                case MSG_SYSTEM_READY:
                    onSystemReady();
                    mWakeLock.release();
                    break;
            }
        }
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
    private void setDevicesState(
            int headsetState, int prevHeadsetState, String headsetName) {
        synchronized (mLock) {
            int allHeadsets = SUPPORTED_HEADSETS;
            for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
                if ((curHeadset & allHeadsets) != 0) {
                //seDeviceStateLocked()
                    setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState, headsetName);
                    allHeadsets &= ~curHeadset;
                }
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
    private void setDeviceStateLocked(int headset,
            int headsetState, int prevHeadsetState, String headsetName) {
        if ((headsetState & headset) != (prevHeadsetState & headset)) {
            int outDevice = 0;
            int inDevice = 0;
            int state;

            if ((headsetState & headset) != 0) {
                state = 1;
            } else {
                state = 0;
            }

            if (headset == BIT_HEADSET) {
                outDevice = AudioManager.DEVICE_OUT_WIRED_HEADSET;
                inDevice = AudioManager.DEVICE_IN_WIRED_HEADSET;
            } else if (headset == BIT_HEADSET_NO_MIC){
                outDevice = AudioManager.DEVICE_OUT_WIRED_HEADPHONE;
            } else if (headset == BIT_LINEOUT){
                outDevice = AudioManager.DEVICE_OUT_LINE;
            } else if (headset == BIT_USB_HEADSET_ANLG) {
                outDevice = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET;
            } else if (headset == BIT_USB_HEADSET_DGTL) {
                outDevice = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET;
            } else if (headset == BIT_HDMI_AUDIO) {
                outDevice = AudioManager.DEVICE_OUT_HDMI;
            } else {
                Slog.e(TAG, "setDeviceState() invalid headset type: "+headset);
                return;
            }

            if (LOG) {
                Slog.v(TAG, "headsetName: " + headsetName +
                        (state == 1 ? " connected" : " disconnected"));
            }
        if(prevHeadsetState == 2 && headsetState == 1 && state == 0) {
                 try {
                      Thread.sleep(136);
                      } catch (InterruptedException e) {
                      // Ingore
                      }
            }
            if (outDevice != 0) {
              mAudioManager.setWiredDeviceConnectionState(outDevice, state, "", headsetName);
            }
            if (inDevice != 0) {
            //經過一系列判斷,最終交給AudioManager
              mAudioManager.setWiredDeviceConnectionState(inDevice, state, "", headsetName);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

@2.2.4 AudioManager—> setWiredDeviceConnectionState()

     /**
     * Indicate wired accessory connection state change.
     * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
     * @param state  new connection state: 1 connected, 0 disconnected
     * @param name   device name
     * {@hide}
     */
    public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
        IAudioService service = getService();
        try {
            service.setWiredDeviceConnectionState(type, state, address, name,
                    mApplicationContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

service指的是AudioService,直接到AudioService中查看

    public void setWiredDeviceConnectionState(int type, int state, String address, String name,
            String caller) {
        synchronized (mConnectedDevices) {
            if (DEBUG_DEVICES) {
                Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
                        + address + ")");
            }
            int delay = checkSendBecomingNoisyIntent(type, state);
            //@ 111
            queueMsgUnderWakeLock(mAudioHandler,
                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
                    0,
                    0,
                    new WiredDeviceConnectionState(type, state, address, name, caller),
                    delay);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
    private void queueMsgUnderWakeLock(Handler handler, int msg,
            int arg1, int arg2, Object obj, int delay) {
        final long ident = Binder.clearCallingIdentity();
        // Always acquire the wake lock as AudioService because it is released by the
        // message handler.
        mAudioEventWakeLock.acquire();
        Binder.restoreCallingIdentity(ident);
        //@ 222
        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
 @Override
        public void handleMessage(Message msg) {
......
......
case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
                    {   WiredDeviceConnectionState connectState =
                            (WiredDeviceConnectionState)msg.obj;
                        onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
                                connectState.mAddress, connectState.mName, connectState.mCaller);
                        mAudioEventWakeLock.release();
                    }
                    break;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
    private static void sendMsg(Handler handler, int msg,
            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {

        if (existingMsgPolicy == SENDMSG_REPLACE) {
            handler.removeMessages(msg);
        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
            return;
        }
        synchronized (mLastDeviceConnectMsgTime) {
            long time = SystemClock.uptimeMillis() + delay;
            handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
            if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
                    msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
                    msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
                mLastDeviceConnectMsgTime = time;
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
 private void onSetWiredDeviceConnectionState(int device, int state, String name)
    {
        synchronized (mConnectedDevices) {
            //state==0 ===> the device is disconnected.
            ...  //ignore BluetoothA2dp Device.
            ...
            handleDeviceConnection((state == 1)/*FULAIRY ADD :true if connected , false if disconnected */, device, (isUsb ? name : ""/* FuLaiRy add :that's why we get empty string when we use common headset.*/));
            ... // other conditions we also ignore  
            // FuLAIRY ADD :Send broadcast ...
            if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
                sendDeviceConnectionIntent(device, state, name);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

上面有兩個重要的函數,分別是handleDeviceConnection和sendDeviceConnectionIntent

首先看handleDeviceConnection,這個函數處理耳機拔插時間

 private boolean handleDeviceConnection(boolean connected, int device, String params) {
      synchronized (mConnectedDevices) {
          //Fulairy: mConnectedDevices is a hashMap :
          //private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();

          // the if means that if key and values are all equal,indicate the same device has been connected .
          boolean isConnected = (mConnectedDevices.containsKey(device) &&
                  (params.isEmpty() || mConnectedDevices.get(device).equals(params)));

          if (isConnected && !connected) {
              //耳機拔出
              AudioSystem.setDeviceConnectionState(device,
                                            AudioSystem.DEVICE_STATE_UNAVAILABLE,
                                            mConnectedDevices.get(device));
               mConnectedDevices.remove(device);
               return true;
          } else if (!isConnected && connected) {
               //耳機連接
               //接下來的處理在JNI方法
               AudioSystem.setDeviceConnectionState(device,
                                                    AudioSystem.DEVICE_STATE_AVAILABLE,
                                                    params);
               mConnectedDevices.put(new Integer(device), params);
               return true;
          }
      }
      return false;
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

然後看sendDeviceConnectionIntent,這個函數向上層發送了一個有序廣播,裏面攜帶了耳機各個信息:是否帶麥、是否連接等等,上層應用可以聽過接收ACTION_HEADSET_PLUG這個廣播進而解析耳機插入時攜帶的內容。

private void sendDeviceConnectionIntent(int device, int state, String name)
  {
      Intent intent = new Intent();

      intent.putExtra("state", state); 
      intent.putExtra("name", name);
      intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);

      int connType = 0;

      if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
          connType = AudioRoutesInfo.MAIN_HEADSET;
          intent.setAction(Intent.ACTION_HEADSET_PLUG);
          intent.putExtra("microphone", 1);
      } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
                 device == AudioSystem.DEVICE_OUT_LINE) {
          /*do apps care about line-out vs headphones?*/
          connType = AudioRoutesInfo.MAIN_HEADPHONES;
          intent.setAction(Intent.ACTION_HEADSET_PLUG);
          intent.putExtra("microphone", 0);
      } ...
      ... 割捨了也很重要的一些其他邏輯處理。
      try {
          ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL); // 後面的流程就不繼續跟了,這個是通用,單獨分出一條線比較好,check裏面是如何運作的。
      } finally ...
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

上面一通分析可能比較混亂,現在梳理一下整個函數調用與信息傳遞過程。 
IMS.notifySwitch()—> 
WiredAccessoryManager.updateLocked() —> 
WiredAccessoryManager.setDevicesState() —> 
WiredAccessoryManager.setDeviceStateLocked()—> 
AudioManager.setWiredDeviceConnectionState()—> 
AudioService.setWiredDeviceConnectionState()—> 
AudioService.onSetWiredDeviceConnectionState()—> 
handleDeviceConnection; sendDeviceConnectionIntent

可以看出來,最終所有的操作都是在AudioSerice這個大管家裏面執行的,其中,handleDeviceConnection是用來更新系統的耳機連接狀態的,sendDeviceConnectionIntent是用來像整個系統發送耳機狀態信息的,包括是否帶麥,能否連接等等。

到此爲止,我們已經將耳機拔插事件的傳遞流程全部理清,裏面還有部分內容需要深入探討,這裏不做分析,關於狀態欄耳機圖標顯示錯誤的問題,主要涉及的是SystemUi的內容,放在下一章講解。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章