Merge "Add Multi Audio focus" into rvc-dev am: 35f960dff4

Change-Id: I3735830ec3076513ce31b580bc90ec947eed2f3f
This commit is contained in:
TreeHugger Robot
2020-04-14 06:46:38 +00:00
committed by Automerger Merge Worker
6 changed files with 165 additions and 10 deletions

8
core/java/android/provider/Settings.java Normal file → Executable file
View File

@@ -4747,6 +4747,14 @@ public final class Settings {
*/
public static final String SHOW_BATTERY_PERCENT = "status_bar_show_battery_percent";
/**
* Whether or not to enable multiple audio focus.
* When enabled, requires more management by user over application playback activity,
* for instance pausing media apps when another starts.
* @hide
*/
public static final String MULTI_AUDIO_FOCUS_ENABLED = "multi_audio_focus_enabled";
/**
* IMPORTANT: If you add a new public settings you also have to add it to
* PUBLIC_SETTINGS below. If the new setting is hidden you have to add

11
media/java/android/media/AudioManager.java Normal file → Executable file
View File

@@ -6145,6 +6145,17 @@ public class AudioManager {
}
}
/** @hide
* TODO: make this a @SystemApi */
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setMultiAudioFocusEnabled(boolean enabled) {
try {
getService().setMultiAudioFocusEnabled(enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
//---------------------------------------------------------
// Inner classes
//--------------------

2
media/java/android/media/IAudioService.aidl Normal file → Executable file
View File

@@ -301,4 +301,6 @@ interface IAudioService {
// WARNING: read warning at top of file, new methods that need to be used by native
// code via IAudioManager.h need to be added to the top section.
oneway void setMultiAudioFocusEnabled(in boolean enabled);
}

View File

@@ -101,7 +101,8 @@ public class SettingsBackupTest {
Settings.System.MIN_REFRESH_RATE, // depends on hardware capabilities
Settings.System.PEAK_REFRESH_RATE, // depends on hardware capabilities
Settings.System.SCREEN_BRIGHTNESS_FLOAT,
Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT
Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT,
Settings.System.MULTI_AUDIO_FOCUS_ENABLED // form-factor/OEM specific
);
private static final Set<String> BACKUP_BLACKLISTED_GLOBAL_SETTINGS =

View File

@@ -8418,6 +8418,23 @@ public class AudioService extends IAudioService.Stub
AudioSystem.setAudioHalPids(pidsArray);
}
//======================
// Multi Audio Focus
//======================
public void setMultiAudioFocusEnabled(boolean enabled) {
enforceModifyAudioRoutingPermission();
if (mMediaFocusControl != null) {
boolean mafEnabled = mMediaFocusControl.getMultiAudioFocusEnabled();
if (mafEnabled != enabled) {
mMediaFocusControl.updateMultiAudioFocus(enabled);
if (!enabled) {
mDeviceBroker.postBroadcastBecomingNoisy();
}
}
}
}
//======================
// misc
//======================

View File

@@ -30,6 +30,7 @@ import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -80,6 +81,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
private final Context mContext;
private final AppOpsManager mAppOps;
private PlayerFocusEnforcer mFocusEnforcer; // never null
private boolean mMultiAudioFocusEnabled = false;
private boolean mRingOrCallActive = false;
@@ -91,6 +93,8 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
mContext = cntxt;
mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
mFocusEnforcer = pfe;
mMultiAudioFocusEnabled = Settings.System.getInt(mContext.getContentResolver(),
Settings.System.MULTI_AUDIO_FOCUS_ENABLED, 0) != 0;
}
protected void dump(PrintWriter pw) {
@@ -100,6 +104,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
pw.println("\n");
// log
mEventLogger.dump(pw);
dumpMultiAudioFocus(pw);
}
//=================================================================
@@ -194,6 +199,14 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
mFocusStack.peek().handleFocusGain(AudioManager.AUDIOFOCUS_GAIN);
}
}
if (mMultiAudioFocusEnabled && !mMultiAudioFocusList.isEmpty()) {
for (FocusRequester multifr : mMultiAudioFocusList) {
if (isLockedFocusOwner(multifr)) {
multifr.handleFocusGain(AudioManager.AUDIOFOCUS_GAIN);
}
}
}
}
/**
@@ -203,17 +216,30 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
*/
@GuardedBy("mAudioFocusLock")
private void propagateFocusLossFromGain_syncAf(int focusGain, final FocusRequester fr,
boolean forceDuck) {
boolean forceDuck) {
final List<String> clientsToRemove = new LinkedList<String>();
// going through the audio focus stack to signal new focus, traversing order doesn't
// matter as all entries respond to the same external focus gain
for (FocusRequester focusLoser : mFocusStack) {
final boolean isDefinitiveLoss =
focusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck);
if (isDefinitiveLoss) {
clientsToRemove.add(focusLoser.getClientId());
if (!mFocusStack.empty()) {
for (FocusRequester focusLoser : mFocusStack) {
final boolean isDefinitiveLoss =
focusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck);
if (isDefinitiveLoss) {
clientsToRemove.add(focusLoser.getClientId());
}
}
}
if (mMultiAudioFocusEnabled && !mMultiAudioFocusList.isEmpty()) {
for (FocusRequester multifocusLoser : mMultiAudioFocusList) {
final boolean isDefinitiveLoss =
multifocusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck);
if (isDefinitiveLoss) {
clientsToRemove.add(multifocusLoser.getClientId());
}
}
}
for (String clientToRemove : clientsToRemove) {
removeFocusStackEntry(clientToRemove, false /*signal*/,
true /*notifyFocusFollowers*/);
@@ -222,6 +248,8 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
private final Stack<FocusRequester> mFocusStack = new Stack<FocusRequester>();
ArrayList<FocusRequester> mMultiAudioFocusList = new ArrayList<FocusRequester>();
/**
* Helper function:
* Display in the log the current entries in the audio focus stack
@@ -287,6 +315,22 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
}
}
}
if (mMultiAudioFocusEnabled && !mMultiAudioFocusList.isEmpty()) {
Iterator<FocusRequester> listIterator = mMultiAudioFocusList.iterator();
while (listIterator.hasNext()) {
FocusRequester fr = listIterator.next();
if (fr.hasSameClient(clientToRemove)) {
listIterator.remove();
fr.release();
}
}
if (signal) {
// notify the new top of the stack it gained focus
notifyTopOfAudioFocusStack();
}
}
}
/**
@@ -410,6 +454,16 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
removeFocusEntryForExtPolicy(mCb);
} else {
removeFocusStackEntryOnDeath(mCb);
if (mMultiAudioFocusEnabled && !mMultiAudioFocusList.isEmpty()) {
Iterator<FocusRequester> listIterator = mMultiAudioFocusList.iterator();
while (listIterator.hasNext()) {
FocusRequester fr = listIterator.next();
if (fr.hasSameBinder(mCb)) {
listIterator.remove();
fr.release();
}
}
}
}
}
}
@@ -867,6 +921,35 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb,
clientId, afdh, callingPackageName, Binder.getCallingUid(), this, sdk);
if (mMultiAudioFocusEnabled
&& (focusChangeHint == AudioManager.AUDIOFOCUS_GAIN)) {
if (enteringRingOrCall) {
if (!mMultiAudioFocusList.isEmpty()) {
for (FocusRequester multifr : mMultiAudioFocusList) {
multifr.handleFocusLossFromGain(focusChangeHint, nfr, forceDuck);
}
}
} else {
boolean needAdd = true;
if (!mMultiAudioFocusList.isEmpty()) {
for (FocusRequester multifr : mMultiAudioFocusList) {
if (multifr.getClientUid() == Binder.getCallingUid()) {
needAdd = false;
break;
}
}
}
if (needAdd) {
mMultiAudioFocusList.add(nfr);
}
nfr.handleFocusGainFromRequest(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(),
AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
}
if (focusGrantDelayed) {
// focusGrantDelayed being true implies we can't reassign focus right now
// which implies the focus stack is not empty.
@@ -877,9 +960,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
return requestResult;
} else {
// propagate the focus change through the stack
if (!mFocusStack.empty()) {
propagateFocusLossFromGain_syncAf(focusChangeHint, nfr, forceDuck);
}
propagateFocusLossFromGain_syncAf(focusChangeHint, nfr, forceDuck);
// push focus requester at the top of the audio focus stack
mFocusStack.push(nfr);
@@ -970,4 +1051,39 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
}
}.start();
}
public void updateMultiAudioFocus(boolean enabled) {
Log.d(TAG, "updateMultiAudioFocus( " + enabled + " )");
mMultiAudioFocusEnabled = enabled;
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.MULTI_AUDIO_FOCUS_ENABLED, enabled ? 1 : 0);
if (!mFocusStack.isEmpty()) {
final FocusRequester fr = mFocusStack.peek();
fr.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS, null, false);
}
if (!enabled) {
if (!mMultiAudioFocusList.isEmpty()) {
for (FocusRequester multifr : mMultiAudioFocusList) {
multifr.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS, null, false);
}
mMultiAudioFocusList.clear();
}
}
}
public boolean getMultiAudioFocusEnabled() {
return mMultiAudioFocusEnabled;
}
private void dumpMultiAudioFocus(PrintWriter pw) {
pw.println("Multi Audio Focus enabled :" + mMultiAudioFocusEnabled);
if (!mMultiAudioFocusList.isEmpty()) {
pw.println("Multi Audio Focus List:");
pw.println("------------------------------");
for (FocusRequester multifr : mMultiAudioFocusList) {
multifr.dump(pw);
}
pw.println("------------------------------");
}
}
}