Merge "AudioPolicy: focus stack query, send focus loss APIs"
This commit is contained in:
committed by
Android (Google) Code Review
commit
b337200ef4
@@ -5875,9 +5875,11 @@ package android.media.audiopolicy {
|
||||
method public android.media.AudioTrack createAudioTrackSource(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
|
||||
method public int detachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>);
|
||||
method public int getFocusDuckingBehavior();
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioFocusInfo> getFocusStack();
|
||||
method public int getStatus();
|
||||
method public boolean removeUidDeviceAffinity(int);
|
||||
method public boolean removeUserIdDeviceAffinity(int);
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean sendFocusLoss(@NonNull android.media.AudioFocusInfo) throws java.lang.IllegalStateException;
|
||||
method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
|
||||
method public void setRegistration(String);
|
||||
method public boolean setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
|
||||
|
||||
@@ -460,4 +460,8 @@ interface IAudioService {
|
||||
boolean register);
|
||||
|
||||
void setTestDeviceConnectionState(in AudioDeviceAttributes device, boolean connected);
|
||||
|
||||
List<AudioFocusInfo> getFocusStack();
|
||||
|
||||
boolean sendFocusLoss(in AudioFocusInfo focusLoser, in IAudioPolicyCallback apcb);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.media.audiopolicy;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.TestApi;
|
||||
import android.annotation.UserIdInt;
|
||||
@@ -230,7 +231,7 @@ public class AudioPolicy {
|
||||
* If set to {@code true}, it is mandatory to set an
|
||||
* {@link AudioPolicy.AudioPolicyFocusListener} in order to successfully build
|
||||
* an {@code AudioPolicy} instance.
|
||||
* @param enforce true if the policy will govern audio focus decisions.
|
||||
* @param isFocusPolicy true if the policy will govern audio focus decisions.
|
||||
* @return the same Builder instance.
|
||||
*/
|
||||
@NonNull
|
||||
@@ -722,6 +723,45 @@ public class AudioPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of entries in the focus stack.
|
||||
* The list is ordered with increasing rank of focus ownership, where the last entry is at the
|
||||
* top of the focus stack and is the current focus owner.
|
||||
* @return the ordered list of focus owners
|
||||
* @see AudioManager#registerAudioPolicy(AudioPolicy)
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||
public @NonNull List<AudioFocusInfo> getFocusStack() {
|
||||
try {
|
||||
return getService().getFocusStack();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send AUDIOFOCUS_LOSS to a specific stack entry, causing it to be notified of the focus
|
||||
* loss, and for it to exit the focus stack (its focus listener will not be invoked after that).
|
||||
* This operation is only valid for a registered policy (with
|
||||
* {@link AudioManager#registerAudioPolicy(AudioPolicy)}) that is also set as the policy focus
|
||||
* listener (with {@link Builder#setAudioPolicyFocusListener(AudioPolicyFocusListener)}.
|
||||
* @param focusLoser the stack entry that is exiting the stack through a focus loss
|
||||
* @return false if the focusLoser wasn't found in the stack, true otherwise
|
||||
* @throws IllegalStateException if used on an unregistered policy, or a registered policy
|
||||
* with no {@link AudioPolicyFocusListener} set
|
||||
* @see AudioManager#registerAudioPolicy(AudioPolicy)
|
||||
* @see Builder#setAudioPolicyStatusListener(AudioPolicyStatusListener)
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||
public boolean sendFocusLoss(@NonNull AudioFocusInfo focusLoser) throws IllegalStateException {
|
||||
Objects.requireNonNull(focusLoser);
|
||||
try {
|
||||
return getService().sendFocusLoss(focusLoser, cb());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AudioRecord} instance that is associated with the given {@link AudioMix}.
|
||||
* Audio buffers recorded through the created instance will contain the mix of the audio
|
||||
|
||||
@@ -10142,6 +10142,27 @@ public class AudioService extends IAudioService.Stub
|
||||
return AudioManager.SUCCESS;
|
||||
}
|
||||
|
||||
/** @see AudioPolicy#getFocusStack() */
|
||||
public List<AudioFocusInfo> getFocusStack() {
|
||||
enforceModifyAudioRoutingPermission();
|
||||
return mMediaFocusControl.getFocusStack();
|
||||
}
|
||||
|
||||
/** @see AudioPolicy#sendFocusLoss */
|
||||
public boolean sendFocusLoss(@NonNull AudioFocusInfo focusLoser,
|
||||
@NonNull IAudioPolicyCallback apcb) {
|
||||
Objects.requireNonNull(focusLoser);
|
||||
Objects.requireNonNull(apcb);
|
||||
enforceModifyAudioRoutingPermission();
|
||||
if (!mAudioPolicies.containsKey(apcb.asBinder())) {
|
||||
throw new IllegalStateException("Only registered AudioPolicy can change focus");
|
||||
}
|
||||
if (!mAudioPolicies.get(apcb.asBinder()).mHasFocusListener) {
|
||||
throw new IllegalStateException("AudioPolicy must have focus listener to change focus");
|
||||
}
|
||||
return mMediaFocusControl.sendFocusLoss(focusLoser);
|
||||
}
|
||||
|
||||
/** see AudioManager.hasRegisteredDynamicPolicy */
|
||||
public boolean hasRegisteredDynamicPolicy() {
|
||||
synchronized (mAudioPolicies) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.media.AudioManager;
|
||||
import android.media.AudioSystem;
|
||||
import android.media.IAudioFocusDispatcher;
|
||||
import android.media.MediaMetrics;
|
||||
import android.media.audiopolicy.AudioPolicy;
|
||||
import android.media.audiopolicy.IAudioPolicyCallback;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
@@ -221,6 +222,51 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of the focus stack for external consumption (composed of AudioFocusInfo
|
||||
* instead of FocusRequester instances)
|
||||
* @return a SystemApi-friendly version of the focus stack, in the same order (last entry
|
||||
* is top of focus stack, i.e. latest focus owner)
|
||||
* @see AudioPolicy#getFocusStack()
|
||||
*/
|
||||
@NonNull List<AudioFocusInfo> getFocusStack() {
|
||||
synchronized (mAudioFocusLock) {
|
||||
final ArrayList<AudioFocusInfo> stack = new ArrayList<>(mFocusStack.size());
|
||||
for (FocusRequester fr : mFocusStack) {
|
||||
stack.add(fr.toAudioFocusInfo());
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send AUDIOFOCUS_LOSS to a specific stack entry.
|
||||
* Note this method is supporting an external API, and is restricted to LOSS in order to
|
||||
* prevent allowing the stack to be in an invalid state (e.g. entry inside stack has focus)
|
||||
* @param focusLoser the stack entry that is exiting the stack through a focus loss
|
||||
* @return false if the focusLoser wasn't found in the stack, true otherwise
|
||||
* @see AudioPolicy#sendFocusLoss(AudioFocusInfo)
|
||||
*/
|
||||
boolean sendFocusLoss(@NonNull AudioFocusInfo focusLoser) {
|
||||
synchronized (mAudioFocusLock) {
|
||||
FocusRequester loserToRemove = null;
|
||||
for (FocusRequester fr : mFocusStack) {
|
||||
if (fr.getClientId().equals(focusLoser.getClientId())) {
|
||||
fr.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS, null,
|
||||
false /*forceDuck*/);
|
||||
loserToRemove = fr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (loserToRemove != null) {
|
||||
mFocusStack.remove(loserToRemove);
|
||||
loserToRemove.release();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@GuardedBy("mAudioFocusLock")
|
||||
private void notifyTopOfAudioFocusStack() {
|
||||
// notify the top of the stack it gained focus
|
||||
|
||||
Reference in New Issue
Block a user