diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index bcd0398b7836d..567e5fe75c38c 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1553,6 +1553,22 @@ public class AudioManager { return AudioSystem.isSourceActive(MediaRecorder.AudioSource.VOICE_RECOGNITION); } + /** + * @hide + * Checks whether the current audio focus is exclusive. + * @return true if the top of the audio focus stack requested focus + * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} + */ + public boolean isAudioFocusExclusive() { + IAudioService service = getService(); + try { + return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE; + } catch (RemoteException e) { + Log.e(TAG, "Dead object in isAudioFocusExclusive()", e); + return false; + } + } + /** * @hide * If the stream is active locally or remotely, adjust its volume according to the enforced @@ -1770,6 +1786,12 @@ public class AudioManager { } } + /** + * @hide + * Used to indicate no audio focus has been gained or lost. + */ + public static final int AUDIOFOCUS_NONE = 0; + /** * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration. * @see OnAudioFocusChangeListener#onAudioFocusChange(int) @@ -1794,6 +1816,17 @@ public class AudioManager { * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) */ public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; + /** + * @hide + * CANDIDATE FOR PUBLIC API + * Used to indicate a temporary request of audio focus, anticipated to last a short + * amount of time, during which no other applications, or system components, should play + * anything. Examples of exclusive and transient audio focus requests are voice + * memo recording and speech recognition, during which the system shouldn't play any + * notifications, and media playback should have paused. + * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) + */ + public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; /** * Used to indicate a loss of audio focus of unknown duration. * @see OnAudioFocusChangeListener#onAudioFocusChange(int) @@ -1964,8 +1997,8 @@ public class AudioManager { */ public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) { int status = AUDIOFOCUS_REQUEST_FAILED; - if ((durationHint < AUDIOFOCUS_GAIN) || (durationHint > AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)) - { + if ((durationHint < AUDIOFOCUS_GAIN) || + (durationHint > AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) { Log.e(TAG, "Invalid duration hint, audio focus request denied"); return status; } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index c178ae4d03a61..290866e7ea153 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -4198,6 +4198,10 @@ public class AudioService extends IAudioService.Stub { mMediaFocusControl.unregisterAudioFocusClient(clientId); } + public int getCurrentAudioFocus() { + return mMediaFocusControl.getCurrentAudioFocus(); + } + //========================================================================================== // Device orientation //========================================================================================== diff --git a/media/java/android/media/FocusRequester.java b/media/java/android/media/FocusRequester.java index 020f3e1ee9419..9a39994bae702 100644 --- a/media/java/android/media/FocusRequester.java +++ b/media/java/android/media/FocusRequester.java @@ -30,11 +30,6 @@ import java.io.PrintWriter; */ class FocusRequester { - /** - * Used to indicate no audio focus has been gained or lost. - */ - private static final int AUDIOFOCUS_NONE = 0; - // on purpose not using this classe's name, as it will only be used from MediaFocusControl private static final String TAG = "MediaFocusControl"; private static final boolean DEBUG = false; @@ -50,7 +45,7 @@ class FocusRequester { */ private final int mFocusGainRequest; /** - * the audio focus loss received my mFocusDispatcher, is MediaFocusControl.AUDIOFOCUS_NONE if + * the audio focus loss received my mFocusDispatcher, is AudioManager.AUDIOFOCUS_NONE if * it never lost focus. */ private int mFocusLossReceived; @@ -70,7 +65,7 @@ class FocusRequester { mPackageName = pn; mCallingUid = uid; mFocusGainRequest = focusRequest; - mFocusLossReceived = AUDIOFOCUS_NONE; + mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE; } @@ -110,7 +105,7 @@ class FocusRequester { private static String focusChangeToString(int focus) { switch(focus) { - case AUDIOFOCUS_NONE: + case AudioManager.AUDIOFOCUS_NONE: return "none"; case AudioManager.AUDIOFOCUS_GAIN: return "GAIN"; @@ -118,6 +113,8 @@ class FocusRequester { return "GAIN_TRANSIENT"; case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK: return "GAIN_TRANSIENT_MAY_DUCK"; + case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE: + return "GAIN_TRANSIENT_EXCLUSIVE"; case AudioManager.AUDIOFOCUS_LOSS: return "LOSS"; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: @@ -178,21 +175,22 @@ class FocusRequester { case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: case AudioManager.AUDIOFOCUS_LOSS: - case AUDIOFOCUS_NONE: + case AudioManager.AUDIOFOCUS_NONE: return AudioManager.AUDIOFOCUS_LOSS; } + case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE: case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT: switch(mFocusLossReceived) { case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: - case AUDIOFOCUS_NONE: + case AudioManager.AUDIOFOCUS_NONE: return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT; case AudioManager.AUDIOFOCUS_LOSS: return AudioManager.AUDIOFOCUS_LOSS; } case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK: switch(mFocusLossReceived) { - case AUDIOFOCUS_NONE: + case AudioManager.AUDIOFOCUS_NONE: case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: @@ -202,7 +200,7 @@ class FocusRequester { } default: Log.e(TAG, "focusLossForGainRequest() for invalid focus request "+ gainRequest); - return AUDIOFOCUS_NONE; + return AudioManager.AUDIOFOCUS_NONE; } } @@ -220,7 +218,7 @@ class FocusRequester { } mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId); } - mFocusLossReceived = AUDIOFOCUS_NONE; + mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE; } catch (android.os.RemoteException e) { Log.e(TAG, "Failure to signal gain of audio focus due to: ", e); } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 4a1646b77438e..744e32a465d48 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -119,6 +119,8 @@ interface IAudioService { void unregisterAudioFocusClient(String clientId); + int getCurrentAudioFocus(); + oneway void dispatchMediaKeyEvent(in KeyEvent keyEvent); void dispatchMediaKeyEventUnderWakelock(in KeyEvent keyEvent); diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java index c5b110170c3c6..18b5c5c005832 100644 --- a/media/java/android/media/MediaFocusControl.java +++ b/media/java/android/media/MediaFocusControl.java @@ -424,6 +424,15 @@ public class MediaFocusControl implements OnFinished { } } + protected int getCurrentAudioFocus() { + synchronized(mAudioFocusLock) { + if (mFocusStack.empty()) { + return AudioManager.AUDIOFOCUS_NONE; + } else { + return mFocusStack.peek().getGainRequest(); + } + } + } /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int) */ protected int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb, diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index bdf6129f84be3..3ac05fd35d4c8 100644 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -1873,9 +1873,9 @@ public class NotificationManagerService extends INotificationManager.Stub } mSoundNotification = r; // do not play notifications if stream volume is 0 (typically because - // ringer mode is silent) or if speech recognition is active. + // ringer mode is silent) or if there is a user of exclusive audio focus if ((audioManager.getStreamVolume(audioStreamType) != 0) - && !audioManager.isSpeechRecognitionActive()) { + && !audioManager.isAudioFocusExclusive()) { final long identity = Binder.clearCallingIdentity(); try { final IRingtonePlayer player = mAudioService.getRingtonePlayer();