Merge "Audio focus: test APIs for focus injection" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
bbf30df183
@@ -1355,9 +1355,12 @@ package android.media {
|
||||
}
|
||||
|
||||
public class AudioManager {
|
||||
method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int abandonAudioFocusForTest(@NonNull android.media.AudioFocusRequest, @NonNull String);
|
||||
method @Nullable public static android.media.AudioDeviceInfo getDeviceInfoFromType(int);
|
||||
method @IntRange(from=0) @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public long getFadeOutDurationOnFocusLossMillis(@NonNull android.media.AudioAttributes);
|
||||
method public boolean hasRegisteredDynamicPolicy();
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.QUERY_AUDIO_STATE}) public boolean isFullVolumeDevice();
|
||||
method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int requestAudioFocusForTest(@NonNull android.media.AudioFocusRequest, @NonNull String, int, int);
|
||||
}
|
||||
|
||||
public static final class AudioRecord.MetricsConstants {
|
||||
|
||||
@@ -3811,6 +3811,14 @@ public class AudioManager {
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* flag set on test API calls,
|
||||
* see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
|
||||
* note that it isn't used in conjunction with other flags, it is passed as the single
|
||||
* value for flags */
|
||||
public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
|
||||
/** @hide */
|
||||
public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
|
||||
| AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
|
||||
@@ -3970,6 +3978,76 @@ public class AudioManager {
|
||||
return requestAudioFocus(afr, ap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
|
||||
* Used to simulate conditions of the test, not the behavior of the focus requester under test.
|
||||
* @param afr the parameters of the request
|
||||
* @param clientFakeId the identifier of the AudioManager the client would be requesting from
|
||||
* @param clientFakeUid the UID of the client, here an arbitrary int,
|
||||
* doesn't have to be a real UID
|
||||
* @param clientTargetSdk the target SDK used by the client
|
||||
* @return return code indicating status of the request
|
||||
*/
|
||||
@TestApi
|
||||
@RequiresPermission("android.permission.QUERY_AUDIO_STATE")
|
||||
public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
|
||||
@NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
|
||||
Objects.requireNonNull(afr);
|
||||
Objects.requireNonNull(clientFakeId);
|
||||
try {
|
||||
return getService().requestAudioFocusForTest(afr.getAudioAttributes(),
|
||||
afr.getFocusGain(),
|
||||
mICallBack,
|
||||
mAudioFocusDispatcher,
|
||||
clientFakeId, "com.android.test.fakeclient", clientFakeUid, clientTargetSdk);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Test API to abandon audio focus for an arbitrary client.
|
||||
* Used to simulate conditions of the test, not the behavior of the focus requester under test.
|
||||
* @param afr the parameters used for the request
|
||||
* @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
|
||||
* would be requesting
|
||||
* @return return code indicating status of the request
|
||||
*/
|
||||
@TestApi
|
||||
@RequiresPermission("android.permission.QUERY_AUDIO_STATE")
|
||||
public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
|
||||
@NonNull String clientFakeId) {
|
||||
Objects.requireNonNull(afr);
|
||||
Objects.requireNonNull(clientFakeId);
|
||||
try {
|
||||
return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
|
||||
clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Return the duration of the fade out applied when a player of the given AudioAttributes
|
||||
* is losing audio focus
|
||||
* @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
|
||||
* @return a duration in ms, 0 indicates no fade out is applied
|
||||
*/
|
||||
@TestApi
|
||||
@RequiresPermission("android.permission.QUERY_AUDIO_STATE")
|
||||
public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
|
||||
{
|
||||
Objects.requireNonNull(aa);
|
||||
try {
|
||||
return getService().getFadeOutDurationOnFocusLossMillis(aa);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Request or lock audio focus.
|
||||
|
||||
@@ -374,4 +374,13 @@ interface IAudioService {
|
||||
long getAdditionalOutputDeviceDelay(in AudioDeviceAttributes device);
|
||||
|
||||
long getMaxAdditionalOutputDeviceDelay(in AudioDeviceAttributes device);
|
||||
|
||||
int requestAudioFocusForTest(in AudioAttributes aa, int durationHint, IBinder cb,
|
||||
in IAudioFocusDispatcher fd, in String clientId, in String callingPackageName,
|
||||
int uid, int sdk);
|
||||
|
||||
int abandonAudioFocusForTest(in IAudioFocusDispatcher fd, in String clientId,
|
||||
in AudioAttributes aa, in String callingPackageName);
|
||||
|
||||
long getFadeOutDurationOnFocusLossMillis(in AudioAttributes aa);
|
||||
}
|
||||
|
||||
@@ -7907,7 +7907,24 @@ public class AudioService extends IAudioService.Stub
|
||||
mmi.record();
|
||||
return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
|
||||
clientId, callingPackageName, flags, sdk,
|
||||
forceFocusDuckingForAccessibility(aa, durationHint, uid));
|
||||
forceFocusDuckingForAccessibility(aa, durationHint, uid), -1 /*testUid, ignored*/);
|
||||
}
|
||||
|
||||
/** see {@link AudioManager#requestAudioFocusForTest(AudioFocusRequest, String, int, int)} */
|
||||
public int requestAudioFocusForTest(AudioAttributes aa, int durationHint, IBinder cb,
|
||||
IAudioFocusDispatcher fd, String clientId, String callingPackageName,
|
||||
int fakeUid, int sdk) {
|
||||
if (!enforceQueryAudioStateForTest("focus request")) {
|
||||
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||
}
|
||||
if (callingPackageName == null || clientId == null || aa == null) {
|
||||
final String reason = "Invalid null parameter to request audio focus";
|
||||
Log.e(TAG, reason);
|
||||
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||
}
|
||||
return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
|
||||
clientId, callingPackageName, AudioManager.AUDIOFOCUS_FLAG_TEST,
|
||||
sdk, false /*forceDuck*/, fakeUid);
|
||||
}
|
||||
|
||||
public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa,
|
||||
@@ -7927,6 +7944,15 @@ public class AudioService extends IAudioService.Stub
|
||||
return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName);
|
||||
}
|
||||
|
||||
/** see {@link AudioManager#abandonAudioFocusForTest(AudioFocusRequest, String)} */
|
||||
public int abandonAudioFocusForTest(IAudioFocusDispatcher fd, String clientId,
|
||||
AudioAttributes aa, String callingPackageName) {
|
||||
if (!enforceQueryAudioStateForTest("focus abandon")) {
|
||||
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||
}
|
||||
return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName);
|
||||
}
|
||||
|
||||
public void unregisterAudioFocusClient(String clientId) {
|
||||
new MediaMetrics.Item(mMetricsId + "focus")
|
||||
.set(MediaMetrics.Property.CLIENT_NAME, clientId)
|
||||
@@ -7949,6 +7975,25 @@ public class AudioService extends IAudioService.Stub
|
||||
return mMediaFocusControl.hasAudioFocusUsers();
|
||||
}
|
||||
|
||||
/** see {@link AudioManager#getFadeOutDurationOnFocusLossMillis(AudioAttributes)} */
|
||||
public long getFadeOutDurationOnFocusLossMillis(AudioAttributes aa) {
|
||||
if (!enforceQueryAudioStateForTest("fade out duration")) {
|
||||
return 0;
|
||||
}
|
||||
return mMediaFocusControl.getFadeOutDurationOnFocusLossMillis(aa);
|
||||
}
|
||||
|
||||
private boolean enforceQueryAudioStateForTest(String mssg) {
|
||||
if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
|
||||
Manifest.permission.QUERY_AUDIO_STATE)) {
|
||||
final String reason = "Doesn't have QUERY_AUDIO_STATE permission for "
|
||||
+ mssg + " test API";
|
||||
Log.e(TAG, reason, new Exception());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================================
|
||||
private boolean readCameraSoundForced() {
|
||||
return SystemProperties.getBoolean("audio.camerasound.force", false) ||
|
||||
|
||||
@@ -97,6 +97,16 @@ public final class FadeOutManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
static long getFadeOutDurationOnFocusLossMillis(AudioAttributes aa) {
|
||||
if (ArrayUtils.contains(UNFADEABLE_CONTENT_TYPES, aa.getContentType())) {
|
||||
return 0;
|
||||
}
|
||||
if (!ArrayUtils.contains(FADEABLE_USAGES, aa.getUsage())) {
|
||||
return 0;
|
||||
}
|
||||
return FADE_OUT_DURATION_MS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of uid (key) to faded out apps (value)
|
||||
*/
|
||||
|
||||
@@ -862,11 +862,13 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
* @param forceDuck only true if
|
||||
* {@link android.media.AudioFocusRequest.Builder#setFocusGain(int)} was set to true for
|
||||
* accessibility.
|
||||
* @param testUid ignored if flags is not AudioManager.AUDIOFOCUS_FLAG_TEST (strictly equals to)
|
||||
* otherwise the UID being injected for testing
|
||||
* @return
|
||||
*/
|
||||
protected int requestAudioFocus(@NonNull AudioAttributes aa, int focusChangeHint, IBinder cb,
|
||||
IAudioFocusDispatcher fd, @NonNull String clientId, @NonNull String callingPackageName,
|
||||
int flags, int sdk, boolean forceDuck) {
|
||||
int flags, int sdk, boolean forceDuck, int testUid) {
|
||||
new MediaMetrics.Item(mMetricsId)
|
||||
.setUid(Binder.getCallingUid())
|
||||
.set(MediaMetrics.Property.CALLING_PACKAGE, callingPackageName)
|
||||
@@ -878,8 +880,13 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
//.set(MediaMetrics.Property.SDK, sdk)
|
||||
.record();
|
||||
|
||||
// when using the test API, a fake UID can be injected (testUid is ignored otherwise)
|
||||
// note that the test on flags is not a mask test on purpose, AUDIOFOCUS_FLAG_TEST is
|
||||
// supposed to be alone in bitfield
|
||||
final int uid = (flags == AudioManager.AUDIOFOCUS_FLAG_TEST)
|
||||
? testUid : Binder.getCallingUid();
|
||||
mEventLogger.log((new AudioEventLogger.StringEvent(
|
||||
"requestAudioFocus() from uid/pid " + Binder.getCallingUid()
|
||||
"requestAudioFocus() from uid/pid " + uid
|
||||
+ "/" + Binder.getCallingPid()
|
||||
+ " clientId=" + clientId + " callingPack=" + callingPackageName
|
||||
+ " req=" + focusChangeHint
|
||||
@@ -892,8 +899,10 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||
}
|
||||
|
||||
if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
|
||||
callingPackageName) != AppOpsManager.MODE_ALLOWED) {
|
||||
if ((flags != AudioManager.AUDIOFOCUS_FLAG_TEST)
|
||||
// note we're using the real uid for appOp evaluation
|
||||
&& (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
|
||||
callingPackageName) != AppOpsManager.MODE_ALLOWED)) {
|
||||
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||
}
|
||||
|
||||
@@ -910,7 +919,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
final AudioFocusInfo afiForExtPolicy;
|
||||
if (mFocusPolicy != null) {
|
||||
// construct AudioFocusInfo as it will be communicated to audio focus policy
|
||||
afiForExtPolicy = new AudioFocusInfo(aa, Binder.getCallingUid(),
|
||||
afiForExtPolicy = new AudioFocusInfo(aa, uid,
|
||||
clientId, callingPackageName, focusChangeHint, 0 /*lossReceived*/,
|
||||
flags, sdk);
|
||||
} else {
|
||||
@@ -980,7 +989,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
removeFocusStackEntry(clientId, false /* signal */, false /*notifyFocusFollowers*/);
|
||||
|
||||
final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb,
|
||||
clientId, afdh, callingPackageName, Binder.getCallingUid(), this, sdk);
|
||||
clientId, afdh, callingPackageName, uid, this, sdk);
|
||||
|
||||
if (mMultiAudioFocusEnabled
|
||||
&& (focusChangeHint == AudioManager.AUDIOFOCUS_GAIN)) {
|
||||
@@ -1143,6 +1152,13 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
return mMultiAudioFocusEnabled;
|
||||
}
|
||||
|
||||
/*package*/ long getFadeOutDurationOnFocusLossMillis(AudioAttributes aa) {
|
||||
if (!ENFORCE_FADEOUT_FOR_FOCUS_LOSS) {
|
||||
return 0;
|
||||
}
|
||||
return FadeOutManager.getFadeOutDurationOnFocusLossMillis(aa);
|
||||
}
|
||||
|
||||
private void dumpMultiAudioFocus(PrintWriter pw) {
|
||||
pw.println("Multi Audio Focus enabled :" + mMultiAudioFocusEnabled);
|
||||
if (!mMultiAudioFocusList.isEmpty()) {
|
||||
|
||||
@@ -704,6 +704,7 @@ public final class PlaybackActivityMonitor
|
||||
// find which players to fade out
|
||||
synchronized (mPlayerLock) {
|
||||
if (mPlayers.isEmpty()) {
|
||||
if (DEBUG) { Log.v(TAG, "no players to fade out"); }
|
||||
return false;
|
||||
}
|
||||
// check if this UID needs to be faded out (return false if not), and gather list of
|
||||
@@ -731,8 +732,6 @@ public final class PlaybackActivityMonitor
|
||||
apcsToFadeOut.add(apc);
|
||||
}
|
||||
}
|
||||
//###
|
||||
//mDuckingManager.duckUid(loser.getClientUid(), apcsToFadeOut);
|
||||
if (loserHasActivePlayers) {
|
||||
mFadingManager.fadeOutUid(loser.getClientUid(), apcsToFadeOut);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user