diff options
-rw-r--r-- | services/java/com/android/server/HeadsetObserver.java | 102 |
1 files changed, 56 insertions, 46 deletions
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java index 58fa69e..38ccde0 100644 --- a/services/java/com/android/server/HeadsetObserver.java +++ b/services/java/com/android/server/HeadsetObserver.java @@ -43,6 +43,8 @@ class HeadsetObserver extends UEventObserver { private static final int BIT_HEADSET = (1 << 0); private static final int BIT_HEADSET_NO_MIC = (1 << 1); + private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC); + private static final int HEADSETS_WITH_MIC = BIT_HEADSET; private int mHeadsetState; private int mPrevHeadsetState; @@ -100,68 +102,76 @@ class HeadsetObserver extends UEventObserver { private synchronized final void update(String newName, int newState) { // Retain only relevant bits - int headsetState = newState & (BIT_HEADSET|BIT_HEADSET_NO_MIC); + int headsetState = newState & SUPPORTED_HEADSETS; + int newOrOld = headsetState | mHeadsetState; + // reject all suspect transitions: only accept state changes from: + // - a: 0 heaset to 1 headset + // - b: 1 headset to 0 headset + if (mHeadsetState == headsetState || ((newOrOld & (newOrOld - 1)) != 0)) { + return; + } - if (headsetState != mHeadsetState) { - boolean isUnplug = false; - if (((mHeadsetState & BIT_HEADSET) != 0 && (headsetState & BIT_HEADSET) == 0) || - ((mHeadsetState & BIT_HEADSET_NO_MIC) != 0 && (headsetState & BIT_HEADSET_NO_MIC) == 0)) { - isUnplug = true; - } - mHeadsetName = newName; - mPrevHeadsetState = mHeadsetState; - mHeadsetState = headsetState; - mPendingIntent = true; - - if (isUnplug) { - Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY); - mContext.sendBroadcast(intent); - - // It can take hundreds of ms flush the audio pipeline after - // apps pause audio playback, but audio route changes are - // immediate, so delay the route change by 1000ms. - // This could be improved once the audio sub-system provides an - // interface to clear the audio pipeline. - mWakeLock.acquire(); - mHandler.sendEmptyMessageDelayed(0, 1000); - } else { - sendIntent(); - mPendingIntent = false; + mHeadsetName = newName; + mPrevHeadsetState = mHeadsetState; + mHeadsetState = headsetState; + mPendingIntent = true; + + if (headsetState == 0) { + Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY); + mContext.sendBroadcast(intent); + + // It can take hundreds of ms flush the audio pipeline after + // apps pause audio playback, but audio route changes are + // immediate, so delay the route change by 1000ms. + // This could be improved once the audio sub-system provides an + // interface to clear the audio pipeline. + mWakeLock.acquire(); + mHandler.sendEmptyMessageDelayed(0, 1000); + } else { + sendIntents(); + mPendingIntent = false; + } + } + + private synchronized final void sendIntents() { + int allHeadsets = SUPPORTED_HEADSETS; + for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) { + if ((curHeadset & allHeadsets) != 0) { + sendIntent(curHeadset); + allHeadsets &= ~curHeadset; } } } - private synchronized final void sendIntent() { - // Pack up the values and broadcast them to everyone - Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - int state = 0; - int microphone = 0; + private final void sendIntent(int headset) { + if ((mHeadsetState & headset) != (mPrevHeadsetState & headset)) { + // Pack up the values and broadcast them to everyone + Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + int state = 0; + int microphone = 0; - if ((mHeadsetState & BIT_HEADSET) != (mPrevHeadsetState & BIT_HEADSET)) { - microphone = 1; - if ((mHeadsetState & BIT_HEADSET) != 0) { - state = 1; + if ((headset & HEADSETS_WITH_MIC) != 0) { + microphone = 1; } - } else if ((mHeadsetState & BIT_HEADSET_NO_MIC) != (mPrevHeadsetState & BIT_HEADSET_NO_MIC)) { - if ((mHeadsetState & BIT_HEADSET_NO_MIC) != 0) { + if ((mHeadsetState & headset) != 0) { state = 1; } - } + intent.putExtra("state", state); + intent.putExtra("name", mHeadsetName); + intent.putExtra("microphone", microphone); - intent.putExtra("state", state); - intent.putExtra("name", mHeadsetName); - intent.putExtra("microphone", microphone); - - // TODO: Should we require a permission? - ActivityManagerNative.broadcastStickyIntent(intent, null); + if (LOG) Log.v(TAG, "Intent.ACTION_HEADSET_PLUG: state: "+state+" name: "+mHeadsetName+" mic: "+microphone); + // TODO: Should we require a permission? + ActivityManagerNative.broadcastStickyIntent(intent, null); + } } private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { if (mPendingIntent) { - sendIntent(); + sendIntents(); mPendingIntent = false; } mWakeLock.release(); |