diff options
| -rw-r--r-- | api/current.txt | 2 | ||||
| -rw-r--r-- | api/system-current.txt | 9 | ||||
| -rw-r--r-- | api/test-current.txt | 2 | ||||
| -rw-r--r-- | media/java/android/media/AudioFocusRequest.java | 56 | ||||
| -rw-r--r-- | media/java/android/media/AudioManager.java | 252 | ||||
| -rw-r--r-- | media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java | 3 |
6 files changed, 206 insertions, 118 deletions
diff --git a/api/current.txt b/api/current.txt index fb1bb6e84e23..76c9e303125e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -20976,8 +20976,6 @@ package android.media { method public boolean acceptsDelayedFocusGain(); method public android.media.AudioAttributes getAudioAttributes(); method public int getFocusGain(); - method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener(); - method public android.os.Handler getOnAudioFocusChangeListenerHandler(); method public boolean willPauseWhenDucked(); } diff --git a/api/system-current.txt b/api/system-current.txt index a34c2eda8ffd..9480a63dcfa1 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -22729,8 +22729,7 @@ package android.media { method public boolean acceptsDelayedFocusGain(); method public android.media.AudioAttributes getAudioAttributes(); method public int getFocusGain(); - method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener(); - method public android.os.Handler getOnAudioFocusChangeListenerHandler(); + method public boolean locksFocus(); method public boolean willPauseWhenDucked(); } @@ -22741,6 +22740,7 @@ package android.media { method public android.media.AudioFocusRequest.Builder setAcceptsDelayedFocusGain(boolean); method public android.media.AudioFocusRequest.Builder setAudioAttributes(android.media.AudioAttributes); method public android.media.AudioFocusRequest.Builder setFocusGain(int); + method public android.media.AudioFocusRequest.Builder setLocksFocus(boolean); method public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler); method public android.media.AudioFocusRequest.Builder setWillPauseWhenDucked(boolean); } @@ -22821,7 +22821,7 @@ package android.media { public class AudioManager { method public deprecated int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener); - method public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes); + method public deprecated int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes); method public int abandonAudioFocusRequest(android.media.AudioFocusRequest); method public void adjustStreamVolume(int, int, int); method public void adjustSuggestedStreamVolume(int, int, int); @@ -22863,7 +22863,8 @@ package android.media { method public deprecated int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int); method public int requestAudioFocus(android.media.AudioFocusRequest); method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException; - method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException; + method public deprecated int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException; + method public int requestAudioFocus(android.media.AudioFocusRequest, android.media.audiopolicy.AudioPolicy); method public deprecated void setBluetoothA2dpOn(boolean); method public void setBluetoothScoOn(boolean); method public void setMicrophoneMute(boolean); diff --git a/api/test-current.txt b/api/test-current.txt index 34544b1db879..bcf23932d847 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -21078,8 +21078,6 @@ package android.media { method public boolean acceptsDelayedFocusGain(); method public android.media.AudioAttributes getAudioAttributes(); method public int getFocusGain(); - method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener(); - method public android.os.Handler getOnAudioFocusChangeListenerHandler(); method public boolean willPauseWhenDucked(); } diff --git a/media/java/android/media/AudioFocusRequest.java b/media/java/android/media/AudioFocusRequest.java index 73f912b9e6f5..2e4d199e74ce 100644 --- a/media/java/android/media/AudioFocusRequest.java +++ b/media/java/android/media/AudioFocusRequest.java @@ -18,6 +18,7 @@ package android.media; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.media.AudioManager.OnAudioFocusChangeListener; import android.os.Handler; import android.os.Looper; @@ -48,7 +49,6 @@ public final class AudioFocusRequest { private final int mFocusGain; private final int mFlags; - //TODO implement use of optional handler private AudioFocusRequest(OnAudioFocusChangeListener listener, Handler handler, AudioAttributes attr, int focusGain, int flags) { mFocusListener = listener; @@ -77,6 +77,7 @@ public final class AudioFocusRequest { } /** + * @hide * Returns the focus change listener set for this {@code AudioFocusRequest}. * @return null if no {@link AudioManager.OnAudioFocusChangeListener} was set. */ @@ -85,6 +86,7 @@ public final class AudioFocusRequest { } /** + * @hide * Returns the {@link Handler} to be used for the focus change listener. * @return the same {@code Handler} set in. * {@link Builder#setOnAudioFocusChangeListener(OnAudioFocusChangeListener, Handler)}, or null @@ -134,6 +136,18 @@ public final class AudioFocusRequest { == AudioManager.AUDIOFOCUS_FLAG_DELAY_OK; } + /** + * @hide + * Returns whether audio focus will be locked (i.e. focus cannot change) as a result of this + * focus request being successful. + * @return whether this request will lock focus. + */ + @SystemApi + public boolean locksFocus() { + return (mFlags & AudioManager.AUDIOFOCUS_FLAG_LOCK) + == AudioManager.AUDIOFOCUS_FLAG_LOCK; + } + int getFlags() { return mFlags; } @@ -158,9 +172,16 @@ public final class AudioFocusRequest { * ... * mMediaPlayer.setAudioAttributes(mPlaybackAttributes); * ... - * mAudioManager.requestAudioFocus(mFocusRequest); - * ... - * mAudioManager.abandonAudioFocusRequest(mFocusRequest); + * boolean mPlaybackAuthorized = true;; + * int res = mAudioManager.requestAudioFocus(mFocusRequest); + * if (res == AUDIOFOCUS_REQUEST_FAILED) { + * mPlaybackAuthorized = false; + * cancelPlayback(); + * } else if (res == AUDIOFOCUS_REQUEST_DELAYED) { + * playbackDelayed(); + * } else { // res == AUDIOFOCUS_REQUEST_GRANTED + * playbackNow(); + * } * </pre> * */ @@ -171,6 +192,7 @@ public final class AudioFocusRequest { private int mFocusGain; private boolean mPausesOnDuck = false; private boolean mDelayedFocus = false; + private boolean mFocusLocked = false; /** * Constructs a new {@code Builder}, and specifies how audio focus @@ -178,7 +200,8 @@ public final class AudioFocusRequest { * {@link AudioManager#AUDIOFOCUS_GAIN}, {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT}, * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, and * {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}. - * <p>By default there is no focus change listener, and the <code>AudioAttributes</code> + * <p>By default there is no focus change listener, delayed focus is not supported, ducking + * is suitable for the application, and the <code>AudioAttributes</code> * have a usage of {@link AudioAttributes#USAGE_MEDIA}. * @param focusGain the type of audio focus gain that will be requested * @throws IllegalArgumentException thrown when an invalid focus gain type is used @@ -258,11 +281,11 @@ public final class AudioFocusRequest { * in {@code AudioTrack}. * @param attributes the {@link AudioAttributes} for the focus request. * @return this {@code Builder} instance. - * @throws IllegalArgumentException thrown when using null for the attributes. + * @throws NullPointerException thrown when using null for the attributes. */ public @NonNull Builder setAudioAttributes(@NonNull AudioAttributes attributes) { if (attributes == null) { - throw new IllegalArgumentException("Illegal null AudioAttributes"); + throw new NullPointerException("Illegal null AudioAttributes"); } mAttr = attributes; return this; @@ -299,6 +322,22 @@ public final class AudioFocusRequest { } /** + * @hide + * Marks this focus request as locking audio focus so granting is temporarily disabled. + * This feature can only be used by owners of a registered + * {@link android.media.audiopolicy.AudioPolicy} in + * {@link AudioManager#requestAudioFocus(AudioFocusRequest, android.media.audiopolicy.AudioPolicy)}. + * Setting to false is the same as the default behavior. + * @param focusLocked true when locking focus + * @return this {@code Builder} instance + */ + @SystemApi + public @NonNull Builder setLocksFocus(boolean focusLocked) { + mFocusLocked = focusLocked; + return this; + } + + /** * Builds a new {@code AudioFocusRequest} instance combining all the information gathered * by this {@code Builder}'s configuration methods. * @return the {@code AudioFocusRequest} instance qualified by all the properties set @@ -313,7 +352,8 @@ public final class AudioFocusRequest { } final int flags = 0 | (mDelayedFocus ? AudioManager.AUDIOFOCUS_FLAG_DELAY_OK : 0) - | (mPausesOnDuck ? AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS : 0); + | (mPausesOnDuck ? AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS : 0) + | (mFocusLocked ? AudioManager.AUDIOFOCUS_FLAG_LOCK : 0); return new AudioFocusRequest(mFocusListener, mListenerHandler, mAttr, mFocusGain, flags); } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index f13ccc12692d..c7796cdd4cc4 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -18,6 +18,7 @@ package android.media; import android.Manifest; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; @@ -50,9 +51,9 @@ import android.view.KeyEvent; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; /** * AudioManager provides access to volume and ringer mode control. @@ -766,7 +767,7 @@ public class AudioManager { * @see #setStreamVolume(int, int, int) */ public void adjustStreamVolume(int streamType, int direction, int flags) { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.adjustStreamVolume(streamType, direction, flags, getContext().getOpPackageName()); @@ -834,7 +835,7 @@ public class AudioManager { /** @hide */ public void setMasterMute(boolean mute, int flags) { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.setMasterMute(mute, flags, getContext().getOpPackageName(), UserHandle.getCallingUserId()); @@ -851,7 +852,7 @@ public class AudioManager { * @see #setRingerMode(int) */ public int getRingerMode() { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.getRingerModeExternal(); } catch (RemoteException e) { @@ -871,7 +872,7 @@ public class AudioManager { if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) { return false; } - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.isValidRingerMode(ringerMode); } catch (RemoteException e) { @@ -887,7 +888,7 @@ public class AudioManager { * @see #getStreamVolume(int) */ public int getStreamMaxVolume(int streamType) { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.getStreamMaxVolume(streamType); } catch (RemoteException e) { @@ -904,7 +905,7 @@ public class AudioManager { * @hide */ public int getStreamMinVolume(int streamType) { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.getStreamMinVolume(streamType); } catch (RemoteException e) { @@ -921,7 +922,7 @@ public class AudioManager { * @see #setStreamVolume(int, int, int) */ public int getStreamVolume(int streamType) { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.getStreamVolume(streamType); } catch (RemoteException e) { @@ -935,7 +936,7 @@ public class AudioManager { * @hide */ public int getLastAudibleStreamVolume(int streamType) { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.getLastAudibleStreamVolume(streamType); } catch (RemoteException e) { @@ -950,7 +951,7 @@ public class AudioManager { * @hide */ public int getUiSoundsStreamType() { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.getUiSoundsStreamType(); } catch (RemoteException e) { @@ -978,7 +979,7 @@ public class AudioManager { if (!isValidRingerMode(ringerMode)) { return; } - IAudioService service = getService(); + final IAudioService service = getService(); try { service.setRingerModeExternal(ringerMode, getContext().getOpPackageName()); } catch (RemoteException e) { @@ -1002,7 +1003,7 @@ public class AudioManager { * @see #isVolumeFixed() */ public void setStreamVolume(int streamType, int index, int flags) { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName()); } catch (RemoteException e) { @@ -1079,7 +1080,7 @@ public class AudioManager { * @see #adjustStreamVolume(int, int, int) */ public boolean isStreamMute(int streamType) { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.isStreamMute(streamType); } catch (RemoteException e) { @@ -1093,7 +1094,7 @@ public class AudioManager { * @hide */ public boolean isMasterMute() { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.isMasterMute(); } catch (RemoteException e) { @@ -1109,7 +1110,7 @@ public class AudioManager { * @hide */ public void forceVolumeControlStream(int streamType) { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.forceVolumeControlStream(streamType, mICallBack); } catch (RemoteException e) { @@ -1137,7 +1138,7 @@ public class AudioManager { * current ringer mode that can be queried via {@link #getRingerMode()}. */ public boolean shouldVibrate(int vibrateType) { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.shouldVibrate(vibrateType); } catch (RemoteException e) { @@ -1163,7 +1164,7 @@ public class AudioManager { * current ringer mode that can be queried via {@link #getRingerMode()}. */ public int getVibrateSetting(int vibrateType) { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.getVibrateSetting(vibrateType); } catch (RemoteException e) { @@ -1190,7 +1191,7 @@ public class AudioManager { * current ringer mode that can be queried via {@link #getRingerMode()}. */ public void setVibrateSetting(int vibrateType, int vibrateSetting) { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.setVibrateSetting(vibrateType, vibrateSetting); } catch (RemoteException e) { @@ -1208,7 +1209,7 @@ public class AudioManager { * <var>false</var> to turn it off */ public void setSpeakerphoneOn(boolean on){ - IAudioService service = getService(); + final IAudioService service = getService(); try { service.setSpeakerphoneOn(on); } catch (RemoteException e) { @@ -1222,7 +1223,7 @@ public class AudioManager { * @return true if speakerphone is on, false if it's off */ public boolean isSpeakerphoneOn() { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.isSpeakerphoneOn(); } catch (RemoteException e) { @@ -1362,7 +1363,7 @@ public class AudioManager { * @see #ACTION_SCO_AUDIO_STATE_UPDATED */ public void startBluetoothSco(){ - IAudioService service = getService(); + final IAudioService service = getService(); try { service.startBluetoothSco(mICallBack, getContext().getApplicationInfo().targetSdkVersion); @@ -1387,7 +1388,7 @@ public class AudioManager { * @see #ACTION_SCO_AUDIO_STATE_UPDATED */ public void startBluetoothScoVirtualCall() { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.startBluetoothScoVirtualCall(mICallBack); } catch (RemoteException e) { @@ -1406,7 +1407,7 @@ public class AudioManager { */ // Also used for connections started with {@link #startBluetoothScoVirtualCall()} public void stopBluetoothSco(){ - IAudioService service = getService(); + final IAudioService service = getService(); try { service.stopBluetoothSco(mICallBack); } catch (RemoteException e) { @@ -1424,7 +1425,7 @@ public class AudioManager { * <var>false</var> to not use bluetooth SCO for communications */ public void setBluetoothScoOn(boolean on){ - IAudioService service = getService(); + final IAudioService service = getService(); try { service.setBluetoothScoOn(on); } catch (RemoteException e) { @@ -1439,7 +1440,7 @@ public class AudioManager { * false if otherwise */ public boolean isBluetoothScoOn() { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.isBluetoothScoOn(); } catch (RemoteException e) { @@ -1516,7 +1517,7 @@ public class AudioManager { * <var>false</var> to turn mute off */ public void setMicrophoneMute(boolean on) { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.setMicrophoneMute(on, getContext().getOpPackageName(), UserHandle.getCallingUserId()); @@ -1550,7 +1551,7 @@ public class AudioManager { * it can route the audio appropriately. */ public void setMode(int mode) { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName()); } catch (RemoteException e) { @@ -1566,7 +1567,7 @@ public class AudioManager { * Returns the current current audio state from the HAL. */ public int getMode() { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.getMode(); } catch (RemoteException e) { @@ -1703,7 +1704,7 @@ public class AudioManager { * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} */ public boolean isAudioFocusExclusive() { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE; } catch (RemoteException e) { @@ -1869,7 +1870,7 @@ public class AudioManager { return; } - IAudioService service = getService(); + final IAudioService service = getService(); try { service.playSoundEffect(effectType); } catch (RemoteException e) { @@ -1904,7 +1905,7 @@ public class AudioManager { return; } - IAudioService service = getService(); + final IAudioService service = getService(); try { service.playSoundEffect(effectType); } catch (RemoteException e) { @@ -1936,7 +1937,7 @@ public class AudioManager { return; } - IAudioService service = getService(); + final IAudioService service = getService(); try { service.playSoundEffectVolume(effectType, volume); } catch (RemoteException e) { @@ -1958,7 +1959,7 @@ public class AudioManager { * This method must be called when sound effects are enabled. */ public void loadSoundEffects() { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.loadSoundEffects(); } catch (RemoteException e) { @@ -1972,7 +1973,7 @@ public class AudioManager { * sound effects are disabled. */ public void unloadSoundEffects() { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.unloadSoundEffects(); } catch (RemoteException e) { @@ -2058,18 +2059,25 @@ public class AudioManager { } /** - * Map to convert focus event listener IDs, as used in the AudioService audio focus stack, - * to actual listener objects. + * Internal class to hold the AudioFocusRequest as well as the Handler for the callback */ - private final HashMap<String, OnAudioFocusChangeListener> mAudioFocusIdListenerMap = - new HashMap<String, OnAudioFocusChangeListener>(); + private static class FocusRequestInfo { + @NonNull final AudioFocusRequest mRequest; + @Nullable final Handler mHandler; + FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) { + mRequest = afr; + mHandler = handler; + } + } + /** - * Lock to prevent concurrent changes to the list of focus listeners for this AudioManager - * instance. + * Map to convert focus event listener IDs, as used in the AudioService audio focus stack, + * to actual listener objects. */ - private final Object mFocusListenerLock = new Object(); + private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap = + new ConcurrentHashMap<String, FocusRequestInfo>(); - private OnAudioFocusChangeListener findFocusListener(String id) { + private FocusRequestInfo findFocusRequestInfo(String id) { return mAudioFocusIdListenerMap.get(id); } @@ -2110,14 +2118,15 @@ public class AudioManager { public void handleMessage(Message msg) { switch (msg.what) { case MSSG_FOCUS_CHANGE: { - OnAudioFocusChangeListener listener = null; - synchronized(mFocusListenerLock) { - listener = findFocusListener((String)msg.obj); - } - if (listener != null) { - Log.d(TAG, "AudioManager dispatching onAudioFocusChange(" - + msg.arg1 + ") for " + msg.obj); - listener.onAudioFocusChange(msg.arg1); + final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj); + if (fri != null) { + final OnAudioFocusChangeListener listener = + fri.mRequest.getOnAudioFocusChangeListener(); + if (listener != null) { + Log.d(TAG, "dispatching onAudioFocusChange(" + + msg.arg1 + ") to " + msg.obj); + listener.onAudioFocusChange(msg.arg1); + } } } break; case MSSG_RECORDING_CONFIG_CHANGE: { @@ -2153,13 +2162,22 @@ public class AudioManager { } private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() { - + @Override public void dispatchAudioFocusChange(int focusChange, String id) { - final Message m = mServiceEventHandlerDelegate.getHandler().obtainMessage( - MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/, id/*obj*/); - mServiceEventHandlerDelegate.getHandler().sendMessage(m); + final FocusRequestInfo fri = findFocusRequestInfo(id); + if (fri != null) { + final OnAudioFocusChangeListener listener = + fri.mRequest.getOnAudioFocusChangeListener(); + if (listener != null) { + final Handler h = (fri.mHandler == null) ? + mServiceEventHandlerDelegate.getHandler() : fri.mHandler; + final Message m = h.obtainMessage( + MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/, + id/*obj*/); + h.sendMessage(m); + } + } } - }; private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) { @@ -2172,18 +2190,16 @@ public class AudioManager { /** * @hide - * Registers a listener to be called when audio focus changes. Calling this method is optional - * before calling {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, as it - * will register the listener as well if it wasn't registered already. - * @param l the listener to be notified of audio focus changes. - */ - public void registerAudioFocusListener(OnAudioFocusChangeListener l) { - synchronized(mFocusListenerLock) { - if (mAudioFocusIdListenerMap.containsKey(getIdForAudioFocusListener(l))) { - return; - } - mAudioFocusIdListenerMap.put(getIdForAudioFocusListener(l), l); - } + * Registers a listener to be called when audio focus changes and keeps track of the associated + * focus request (including Handler to use for the listener). + * @param afr the full request parameters + */ + public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) { + final Handler h = afr.getOnAudioFocusChangeListenerHandler(); + final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null : + new ServiceEventHandlerDelegate(h).getHandler()); + final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()); + mAudioFocusIdListenerMap.put(key, fri); } /** @@ -2191,12 +2207,9 @@ public class AudioManager { * Causes the specified listener to not be called anymore when focus is gained or lost. * @param l the listener to unregister. */ - public void unregisterAudioFocusListener(OnAudioFocusChangeListener l) { - + public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) { // remove locally - synchronized(mFocusListenerLock) { - mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l)); - } + mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l)); } @@ -2307,15 +2320,10 @@ public class AudioManager { * is requested without building the {@link AudioFocusRequest} with * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to * {@code true}. - * @throws IllegalArgumentException if passed a null argument + * @throws NullPointerException if passed a null argument */ public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) { - if (focusRequest == null) { - throw new IllegalArgumentException("Illegal null AudioFocusRequest"); - } - return requestAudioFocus(focusRequest.getOnAudioFocusChangeListener(), - focusRequest.getAudioAttributes(), - focusRequest.getFocusGain(), focusRequest.getFlags(), null /* no AudioPolicy*/); + return requestAudioFocus(focusRequest, null /* no AudioPolicy*/); } /** @@ -2402,6 +2410,7 @@ public class AudioManager { * @return see the description of the same return value in * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} * @throws IllegalArgumentException + * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)} */ @SystemApi public int requestAudioFocus(OnAudioFocusChangeListener l, @@ -2424,18 +2433,62 @@ public class AudioManager { throw new IllegalArgumentException( "Illegal null focus listener when flagged as accepting delayed focus grant"); } + if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) + == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) { + throw new IllegalArgumentException( + "Illegal null focus listener when flagged as pausing instead of ducking"); + } if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) { throw new IllegalArgumentException( "Illegal null audio policy when locking audio focus"); } - int status = AUDIOFOCUS_REQUEST_FAILED; - registerAudioFocusListener(l); - IAudioService service = getService(); + final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint) + .setOnAudioFocusChangeListener(l, null /* no Handler for this legacy API */) + .setAudioAttributes(requestAttributes) + .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK) + == AUDIOFOCUS_FLAG_DELAY_OK) + .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) + == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) + .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) + .build(); + return requestAudioFocus(afr, ap); + } + + /** + * @hide + * Request or lock audio focus. + * This method is to be used by system components that have registered an + * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it + * so focus granting is temporarily disabled. + * @param afr see the description of the same parameter in + * {@link #requestAudioFocus(AudioFocusRequest)} + * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking + * focus, or null. + * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} + * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. + * @throws NullPointerException if the AudioFocusRequest is null + * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy + */ + @SystemApi + public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) { + if (afr == null) { + throw new NullPointerException("Illegal null AudioFocusRequest"); + } + // this can only be checked now, not during the creation of the AudioFocusRequest instance + if (afr.locksFocus() && ap == null) { + throw new IllegalArgumentException( + "Illegal null audio policy when locking audio focus"); + } + registerAudioFocusRequest(afr); + final IAudioService service = getService(); + final int status; try { - status = service.requestAudioFocus(requestAttributes, durationHint, mICallBack, - mAudioFocusDispatcher, getIdForAudioFocusListener(l), - getContext().getOpPackageName() /* package name */, flags, + status = service.requestAudioFocus(afr.getAudioAttributes(), + afr.getFocusGain(), mICallBack, + mAudioFocusDispatcher, + getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()), + getContext().getOpPackageName() /* package name */, afr.getFlags(), ap != null ? ap.cb() : null); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -2454,7 +2507,7 @@ public class AudioManager { * media applications resume after a call */ public void requestAudioFocusForCall(int streamType, int durationHint) { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.requestAudioFocus(new AudioAttributes.Builder() .setInternalLegacyStreamType(streamType).build(), @@ -2477,7 +2530,7 @@ public class AudioManager { * @return */ public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) { - IAudioService service = getService(); + final IAudioService service = getService(); try { return service.getFocusRampTimeMs(focusGain, attr); } catch (RemoteException e) { @@ -2492,7 +2545,7 @@ public class AudioManager { * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}. */ public void abandonAudioFocusForCall() { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID, null /*AudioAttributes, legacy behavior*/); @@ -2517,12 +2570,13 @@ public class AudioManager { * @param l the listener with which focus was requested. * @param aa the {@link AudioAttributes} with which audio focus was requested * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} + * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)} */ @SystemApi public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) { int status = AUDIOFOCUS_REQUEST_FAILED; - unregisterAudioFocusListener(l); - IAudioService service = getService(); + unregisterAudioFocusRequest(l); + final IAudioService service = getService(); try { status = service.abandonAudioFocus(mAudioFocusDispatcher, getIdForAudioFocusListener(l), aa); @@ -2730,7 +2784,7 @@ public class AudioManager { if (policy == null) { throw new IllegalArgumentException("Illegal null AudioPolicy argument"); } - IAudioService service = getService(); + final IAudioService service = getService(); try { String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(), policy.hasFocusListener()); @@ -2755,7 +2809,7 @@ public class AudioManager { if (policy == null) { throw new IllegalArgumentException("Illegal null AudioPolicy argument"); } - IAudioService service = getService(); + final IAudioService service = getService(); try { service.unregisterAudioPolicyAsync(policy.cb()); policy.setRegistration(null); @@ -2930,7 +2984,7 @@ public class AudioManager { } private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() { - + @Override public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs) { synchronized(mPlaybackCallbackLock) { if (mPlaybackCallbackList != null) { @@ -3124,7 +3178,7 @@ public class AudioManager { } private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() { - + @Override public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) { synchronized(mRecordCallbackLock) { if (mRecordCallbackList != null) { @@ -3152,7 +3206,7 @@ public class AudioManager { * to read and apply restored settings. */ public void reloadAudioSettings() { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.reloadAudioSettings(); } catch (RemoteException e) { @@ -3167,7 +3221,7 @@ public class AudioManager { * them. */ public void avrcpSupportsAbsoluteVolume(String address, boolean support) { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.avrcpSupportsAbsoluteVolume(address, support); } catch (RemoteException e) { @@ -3462,7 +3516,7 @@ public class AudioManager { * {@hide} */ public void setWiredDeviceConnectionState(int type, int state, String address, String name) { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.setWiredDeviceConnectionState(type, state, address, name, mApplicationContext.getOpPackageName()); @@ -3484,7 +3538,7 @@ public class AudioManager { */ public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile) { - IAudioService service = getService(); + final IAudioService service = getService(); int delay = 0; try { delay = service.setBluetoothA2dpDeviceConnectionState(device, state, profile); @@ -3500,7 +3554,7 @@ public class AudioManager { * {@hide} */ public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) { - IAudioService service = getService(); + final IAudioService service = getService(); try { service.handleBluetoothA2dpDeviceConfigChange(device); } catch (RemoteException e) { diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java index e2323386c70c..3a332c67c579 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java @@ -161,13 +161,11 @@ public class MediaAudioManagerTest extends ActivityInstrumentationTestCase2<Medi private void setupAudioFocusListener() { mAudioFocusListener = new AudioFocusListener(); - mAudioManager.registerAudioFocusListener(mAudioFocusListener); } private void cleanupAudioFocusListener() { // clean up mAudioManager.abandonAudioFocus(mAudioFocusListener); - mAudioManager.unregisterAudioFocusListener(mAudioFocusListener); } //---------------------------------- @@ -245,6 +243,5 @@ public class MediaAudioManagerTest extends ActivityInstrumentationTestCase2<Medi mAudioFocusListener.mFocusChangeCounter + " AudioFocus changes", mAudioFocusListener.mFocusChangeCounter == ITERATIONS * 2); mAudioManager.abandonAudioFocus(mAudioFocusListener); - mAudioManager.unregisterAudioFocusListener(mAudioFocusListener); } } |