diff options
Diffstat (limited to 'services/java/com/android/server/HeadsetObserver.java')
-rw-r--r-- | services/java/com/android/server/HeadsetObserver.java | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java index 2bea7312fc53..855734dcb80e 100644 --- a/services/java/com/android/server/HeadsetObserver.java +++ b/services/java/com/android/server/HeadsetObserver.java @@ -19,6 +19,8 @@ package com.android.server; import android.app.ActivityManagerNative; import android.content.Context; import android.content.Intent; +import android.os.Handler; +import android.os.Message; import android.os.UEventObserver; import android.util.Log; import android.media.AudioManager; @@ -40,6 +42,8 @@ class HeadsetObserver extends UEventObserver { private int mHeadsetState; private String mHeadsetName; + private boolean mAudioRouteNeedsUpdate; + private AudioManager mAudioManager; public HeadsetObserver(Context context) { mContext = context; @@ -60,7 +64,7 @@ class HeadsetObserver extends UEventObserver { } } - private final void init() { + private synchronized final void init() { char[] buffer = new char[1024]; String newName = mHeadsetName; @@ -80,21 +84,33 @@ class HeadsetObserver extends UEventObserver { Log.e(TAG, "" , e); } + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); update(newName, newState); } private synchronized final void update(String newName, int newState) { if (newName != mHeadsetName || newState != mHeadsetState) { + boolean isUnplug = (newState == 0 && mHeadsetState == 1); mHeadsetName = newName; mHeadsetState = newState; - AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - - audioManager.setWiredHeadsetOn(mHeadsetState == 1); - sendIntent(); + mAudioRouteNeedsUpdate = true; + + sendIntent(isUnplug); + + if (isUnplug) { + // It often takes >200ms to flush the audio pipeline after apps + // pause audio playback, but audio route changes are immediate, + // so delay the route change by 400ms. + // This could be improved once the audio sub-system provides an + // interface to clear the audio pipeline. + mHandler.sendEmptyMessageDelayed(0, 400); + } else { + updateAudioRoute(); + } } } - private synchronized final void sendIntent() { + private synchronized final void sendIntent(boolean isUnplug) { // Pack up the values and broadcast them to everyone Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); @@ -104,5 +120,25 @@ class HeadsetObserver extends UEventObserver { // TODO: Should we require a permission? ActivityManagerNative.broadcastStickyIntent(intent, null); + + if (isUnplug) { + intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY); + mContext.sendBroadcast(intent); + } } + + private synchronized final void updateAudioRoute() { + if (mAudioRouteNeedsUpdate) { + mAudioManager.setWiredHeadsetOn(mHeadsetState == 1); + mAudioRouteNeedsUpdate = false; + } + } + + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + updateAudioRoute(); + } + }; + } |