Merge "Add Multi Audio focus" into rvc-dev am: 35f960dff4
Change-Id: I3735830ec3076513ce31b580bc90ec947eed2f3f
This commit is contained in:
8
core/java/android/provider/Settings.java
Normal file → Executable file
8
core/java/android/provider/Settings.java
Normal file → Executable 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
11
media/java/android/media/AudioManager.java
Normal file → Executable 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
2
media/java/android/media/IAudioService.aidl
Normal file → Executable 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);
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
17
services/core/java/com/android/server/audio/AudioService.java
Normal file → Executable file
17
services/core/java/com/android/server/audio/AudioService.java
Normal file → Executable 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
|
||||
//======================
|
||||
|
||||
134
services/core/java/com/android/server/audio/MediaFocusControl.java
Normal file → Executable file
134
services/core/java/com/android/server/audio/MediaFocusControl.java
Normal file → Executable 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("------------------------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user