* commit '213472d7384c9d8096748f3cd9305ef49342dbcf': Add support for audio focus locking
This commit is contained in:
@ -17,6 +17,7 @@
|
|||||||
package android.media;
|
package android.media;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.annotation.SdkConstant;
|
import android.annotation.SdkConstant;
|
||||||
import android.annotation.SdkConstant.SdkConstantType;
|
import android.annotation.SdkConstant.SdkConstantType;
|
||||||
import android.annotation.SystemApi;
|
import android.annotation.SystemApi;
|
||||||
@ -2318,14 +2319,25 @@ public class AudioManager {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// when adding new flags, add them to AUDIOFOCUS_FLAGS_ALL
|
// when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
|
||||||
/** @hide */
|
/** @hide */
|
||||||
|
@SystemApi
|
||||||
public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
|
public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public static final int AUDIOFOCUS_FLAGS_ALL = AUDIOFOCUS_FLAG_DELAY_OK;
|
@SystemApi
|
||||||
|
public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 1;
|
||||||
|
/** @hide */
|
||||||
|
public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK;
|
||||||
|
/** @hide */
|
||||||
|
public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
|
||||||
|
| AUDIOFOCUS_FLAG_LOCK;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
|
* Request audio focus.
|
||||||
|
* Send a request to obtain the audio focus. This method differs from
|
||||||
|
* {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
|
||||||
|
* that the requester accepts delayed grants of audio focus.
|
||||||
* @param l the listener to be notified of audio focus changes. It is not allowed to be null
|
* @param l the listener to be notified of audio focus changes. It is not allowed to be null
|
||||||
* when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
|
* when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
|
||||||
* @param requestAttributes non null {@link AudioAttributes} describing the main reason for
|
* @param requestAttributes non null {@link AudioAttributes} describing the main reason for
|
||||||
@ -2340,24 +2352,70 @@ public class AudioManager {
|
|||||||
* usecases such as voice memo recording, or speech recognition.
|
* usecases such as voice memo recording, or speech recognition.
|
||||||
* Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
|
* Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
|
||||||
* as the playback of a song or a video.
|
* as the playback of a song or a video.
|
||||||
* @param flags use 0 when not using any flags for the request, which behaves like
|
* @param flags 0 or {link #AUDIOFOCUS_FLAG_DELAY_OK}.
|
||||||
* {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
|
* <br>Use 0 when not using any flags for the request, which behaves like
|
||||||
* focus is granted immediately, or the grant request fails because the system is in a
|
* {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
|
||||||
* state where focus cannot change (e.g. a phone call).
|
* focus is granted immediately, or the grant request fails because the system is in a
|
||||||
* Use {link #AUDIOFOCUS_FLAG_DELAY_OK} if it is ok for the requester to not be granted
|
* state where focus cannot change (e.g. a phone call).
|
||||||
* audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
|
* <br>Use {link #AUDIOFOCUS_FLAG_DELAY_OK} if it is ok for the requester to not be granted
|
||||||
* the system is in a state where focus cannot change, but be granted focus later when
|
* audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
|
||||||
* this condition ends.
|
* the system is in a state where focus cannot change, but be granted focus later when
|
||||||
|
* this condition ends.
|
||||||
* @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
|
* @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
|
||||||
* or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
|
* or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
|
||||||
* The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
|
* The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
|
||||||
* without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
|
* without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
*/
|
*/
|
||||||
|
@SystemApi
|
||||||
public int requestAudioFocus(OnAudioFocusChangeListener l,
|
public int requestAudioFocus(OnAudioFocusChangeListener l,
|
||||||
AudioAttributes requestAttributes,
|
@NonNull AudioAttributes requestAttributes,
|
||||||
int durationHint,
|
int durationHint,
|
||||||
int flags) throws IllegalArgumentException {
|
int flags) throws IllegalArgumentException {
|
||||||
|
if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
|
||||||
|
throw new IllegalArgumentException("Invalid flags 0x"
|
||||||
|
+ Integer.toHexString(flags).toUpperCase());
|
||||||
|
}
|
||||||
|
return requestAudioFocus(l, requestAttributes, durationHint,
|
||||||
|
flags & AUDIOFOCUS_FLAGS_APPS,
|
||||||
|
null /* no AudioPolicy*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 l see the description of the same parameter in
|
||||||
|
* {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
|
||||||
|
* @param requestAttributes non null {@link AudioAttributes} describing the main reason for
|
||||||
|
* requesting audio focus.
|
||||||
|
* @param durationHint see the description of the same parameter in
|
||||||
|
* {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
|
||||||
|
* @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
|
||||||
|
* {@link #AUDIOFOCUS_FLAG_LOCK}
|
||||||
|
* <br>Use 0 when not using any flags for the request, which behaves like
|
||||||
|
* {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
|
||||||
|
* focus is granted immediately, or the grant request fails because the system is in a
|
||||||
|
* state where focus cannot change (e.g. a phone call).
|
||||||
|
* <br>Use {link #AUDIOFOCUS_FLAG_DELAY_OK} if it is ok for the requester to not be granted
|
||||||
|
* audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
|
||||||
|
* the system is in a state where focus cannot change, but be granted focus later when
|
||||||
|
* this condition ends.
|
||||||
|
* <br>Use {@link #AUDIOFOCUS_FLAG_LOCK} when locking audio focus so granting is
|
||||||
|
* temporarily disabled.
|
||||||
|
* @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
|
||||||
|
* focus, or null.
|
||||||
|
* @return see the description of the same return value in
|
||||||
|
* {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
*/
|
||||||
|
public int requestAudioFocus(OnAudioFocusChangeListener l,
|
||||||
|
@NonNull AudioAttributes requestAttributes,
|
||||||
|
int durationHint,
|
||||||
|
int flags,
|
||||||
|
AudioPolicy ap) throws IllegalArgumentException {
|
||||||
// parameter checking
|
// parameter checking
|
||||||
if (requestAttributes == null) {
|
if (requestAttributes == null) {
|
||||||
throw new IllegalArgumentException("Illegal null AudioAttributes argument");
|
throw new IllegalArgumentException("Illegal null AudioAttributes argument");
|
||||||
@ -2366,7 +2424,7 @@ public class AudioManager {
|
|||||||
(durationHint > AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
|
(durationHint > AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
|
||||||
throw new IllegalArgumentException("Invalid duration hint");
|
throw new IllegalArgumentException("Invalid duration hint");
|
||||||
}
|
}
|
||||||
if (flags != (flags & AUDIOFOCUS_FLAGS_ALL)) {
|
if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
|
||||||
throw new IllegalArgumentException("Illegal flags 0x"
|
throw new IllegalArgumentException("Illegal flags 0x"
|
||||||
+ Integer.toHexString(flags).toUpperCase());
|
+ Integer.toHexString(flags).toUpperCase());
|
||||||
}
|
}
|
||||||
@ -2374,6 +2432,10 @@ public class AudioManager {
|
|||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Illegal null focus listener when flagged as accepting delayed focus grant");
|
"Illegal null focus listener when flagged as accepting delayed focus grant");
|
||||||
}
|
}
|
||||||
|
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;
|
int status = AUDIOFOCUS_REQUEST_FAILED;
|
||||||
registerAudioFocusListener(l);
|
registerAudioFocusListener(l);
|
||||||
@ -2381,9 +2443,10 @@ public class AudioManager {
|
|||||||
try {
|
try {
|
||||||
status = service.requestAudioFocus(requestAttributes, durationHint, mICallBack,
|
status = service.requestAudioFocus(requestAttributes, durationHint, mICallBack,
|
||||||
mAudioFocusDispatcher, getIdForAudioFocusListener(l),
|
mAudioFocusDispatcher, getIdForAudioFocusListener(l),
|
||||||
mContext.getOpPackageName() /* package name */, flags);
|
mContext.getOpPackageName() /* package name */, flags,
|
||||||
|
ap != null ? ap.token() : null);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Can't call requestAudioFocus() on AudioService due to "+e);
|
Log.e(TAG, "Can't call requestAudioFocus() on AudioService:", e);
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -2405,9 +2468,11 @@ public class AudioManager {
|
|||||||
.setInternalLegacyStreamType(streamType).build(),
|
.setInternalLegacyStreamType(streamType).build(),
|
||||||
durationHint, mICallBack, null,
|
durationHint, mICallBack, null,
|
||||||
MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
|
MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
|
||||||
mContext.getOpPackageName(), 0 /* flags, legacy behavior*/ );
|
mContext.getOpPackageName(),
|
||||||
|
AUDIOFOCUS_FLAG_LOCK,
|
||||||
|
null /* policy token */);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e);
|
Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2420,9 +2485,10 @@ public class AudioManager {
|
|||||||
public void abandonAudioFocusForCall() {
|
public void abandonAudioFocusForCall() {
|
||||||
IAudioService service = getService();
|
IAudioService service = getService();
|
||||||
try {
|
try {
|
||||||
service.abandonAudioFocus(null, MediaFocusControl.IN_VOICE_COMM_FOCUS_ID);
|
service.abandonAudioFocus(null, MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
|
||||||
|
null /*AudioAttributes, legacy behavior*/);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService due to "+e);
|
Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2432,19 +2498,30 @@ public class AudioManager {
|
|||||||
* @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
|
* @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
|
||||||
*/
|
*/
|
||||||
public int abandonAudioFocus(OnAudioFocusChangeListener l) {
|
public int abandonAudioFocus(OnAudioFocusChangeListener l) {
|
||||||
|
return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
|
||||||
|
* @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}
|
||||||
|
*/
|
||||||
|
@SystemApi
|
||||||
|
public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
|
||||||
int status = AUDIOFOCUS_REQUEST_FAILED;
|
int status = AUDIOFOCUS_REQUEST_FAILED;
|
||||||
unregisterAudioFocusListener(l);
|
unregisterAudioFocusListener(l);
|
||||||
IAudioService service = getService();
|
IAudioService service = getService();
|
||||||
try {
|
try {
|
||||||
status = service.abandonAudioFocus(mAudioFocusDispatcher,
|
status = service.abandonAudioFocus(mAudioFocusDispatcher,
|
||||||
getIdForAudioFocusListener(l));
|
getIdForAudioFocusListener(l), aa);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Can't call abandonAudioFocus() on AudioService due to "+e);
|
Log.e(TAG, "Can't call abandonAudioFocus() on AudioService:", e);
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//====================================================================
|
//====================================================================
|
||||||
// Remote Control
|
// Remote Control
|
||||||
/**
|
/**
|
||||||
|
@ -49,6 +49,7 @@ import android.hardware.usb.UsbManager;
|
|||||||
import android.media.MediaPlayer.OnCompletionListener;
|
import android.media.MediaPlayer.OnCompletionListener;
|
||||||
import android.media.MediaPlayer.OnErrorListener;
|
import android.media.MediaPlayer.OnErrorListener;
|
||||||
import android.media.audiopolicy.AudioMix;
|
import android.media.audiopolicy.AudioMix;
|
||||||
|
import android.media.audiopolicy.AudioPolicy;
|
||||||
import android.media.audiopolicy.AudioPolicyConfig;
|
import android.media.audiopolicy.AudioPolicyConfig;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@ -5018,13 +5019,34 @@ public class AudioService extends IAudioService.Stub {
|
|||||||
// Audio Focus
|
// Audio Focus
|
||||||
//==========================================================================================
|
//==========================================================================================
|
||||||
public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
|
public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
|
||||||
IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags) {
|
IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
|
||||||
|
IBinder policyToken) {
|
||||||
|
// permission checks
|
||||||
|
if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
|
||||||
|
if (mMediaFocusControl.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
|
||||||
|
if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
|
||||||
|
android.Manifest.permission.MODIFY_PHONE_STATE)) {
|
||||||
|
Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
|
||||||
|
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// only a registered audio policy can be used to lock focus
|
||||||
|
synchronized (mAudioPolicies) {
|
||||||
|
if (!mAudioPolicies.containsKey(policyToken)) {
|
||||||
|
Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus",
|
||||||
|
new Exception());
|
||||||
|
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
|
return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
|
||||||
clientId, callingPackageName, flags);
|
clientId, callingPackageName, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
|
public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
|
||||||
return mMediaFocusControl.abandonAudioFocus(fd, clientId);
|
return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregisterAudioFocusClient(String clientId) {
|
public void unregisterAudioFocusClient(String clientId) {
|
||||||
@ -5725,6 +5747,9 @@ public class AudioService extends IAudioService.Stub {
|
|||||||
// TODO implement clearing mix attribute matching info in native audio policy
|
// TODO implement clearing mix attribute matching info in native audio policy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//======================
|
||||||
|
// Audio policy proxy
|
||||||
|
//======================
|
||||||
/**
|
/**
|
||||||
* This internal class inherits from AudioPolicyConfig which contains all the mixes and
|
* This internal class inherits from AudioPolicyConfig which contains all the mixes and
|
||||||
* their configurations.
|
* their configurations.
|
||||||
@ -5742,8 +5767,8 @@ public class AudioService extends IAudioService.Stub {
|
|||||||
public void binderDied() {
|
public void binderDied() {
|
||||||
synchronized (mAudioPolicies) {
|
synchronized (mAudioPolicies) {
|
||||||
Log.i(TAG, "audio policy " + mToken + " died");
|
Log.i(TAG, "audio policy " + mToken + " died");
|
||||||
mAudioPolicies.remove(mToken);
|
|
||||||
disconnectMixes();
|
disconnectMixes();
|
||||||
|
mAudioPolicies.remove(mToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +83,10 @@ class FocusRequester {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isLockedFocusOwner() {
|
||||||
|
return ((mGrantFlags & AudioManager.AUDIOFOCUS_FLAG_LOCK) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
boolean hasSameBinder(IBinder ib) {
|
boolean hasSameBinder(IBinder ib) {
|
||||||
return (mSourceRef != null) && mSourceRef.equals(ib);
|
return (mSourceRef != null) && mSourceRef.equals(ib);
|
||||||
}
|
}
|
||||||
@ -99,6 +103,9 @@ class FocusRequester {
|
|||||||
return mCallingUid == uid;
|
return mCallingUid == uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getClientId() {
|
||||||
|
return mClientId;
|
||||||
|
}
|
||||||
|
|
||||||
int getGainRequest() {
|
int getGainRequest() {
|
||||||
return mFocusGainRequest;
|
return mFocusGainRequest;
|
||||||
@ -144,12 +151,20 @@ class FocusRequester {
|
|||||||
return focusChangeToString(mFocusLossReceived);
|
return focusChangeToString(mFocusLossReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String flagsToString(int flags) {
|
||||||
|
String msg = new String();
|
||||||
|
if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) != 0) { msg += "DELAY_OK"; }
|
||||||
|
if (!msg.isEmpty()) { msg += "|"; }
|
||||||
|
if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) != 0) { msg += "LOCK"; }
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
void dump(PrintWriter pw) {
|
void dump(PrintWriter pw) {
|
||||||
pw.println(" source:" + mSourceRef
|
pw.println(" source:" + mSourceRef
|
||||||
+ " -- pack: " + mPackageName
|
+ " -- pack: " + mPackageName
|
||||||
+ " -- client: " + mClientId
|
+ " -- client: " + mClientId
|
||||||
+ " -- gain: " + focusGainToString()
|
+ " -- gain: " + focusGainToString()
|
||||||
+ " -- grant: " + mGrantFlags
|
+ " -- flags: " + flagsToString(mGrantFlags)
|
||||||
+ " -- loss: " + focusLossToString()
|
+ " -- loss: " + focusLossToString()
|
||||||
+ " -- uid: " + mCallingUid
|
+ " -- uid: " + mCallingUid
|
||||||
+ " -- attr: " + mAttributes);
|
+ " -- attr: " + mAttributes);
|
||||||
|
@ -118,9 +118,10 @@ interface IAudioService {
|
|||||||
boolean isBluetoothA2dpOn();
|
boolean isBluetoothA2dpOn();
|
||||||
|
|
||||||
int requestAudioFocus(in AudioAttributes aa, int durationHint, IBinder cb,
|
int requestAudioFocus(in AudioAttributes aa, int durationHint, IBinder cb,
|
||||||
IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags);
|
IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
|
||||||
|
IBinder policyToken);
|
||||||
|
|
||||||
int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId);
|
int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, in AudioAttributes aa);
|
||||||
|
|
||||||
void unregisterAudioFocusClient(String clientId);
|
void unregisterAudioFocusClient(String clientId);
|
||||||
|
|
||||||
|
@ -390,7 +390,8 @@ public class MediaFocusControl implements OnFinished {
|
|||||||
// AudioFocus
|
// AudioFocus
|
||||||
//==========================================================================================
|
//==========================================================================================
|
||||||
|
|
||||||
/* constant to identify focus stack entry that is used to hold the focus while the phone
|
/**
|
||||||
|
* Constant to identify a focus stack entry that is used to hold the focus while the phone
|
||||||
* is ringing or during a call. Used by com.android.internal.telephony.CallManager when
|
* is ringing or during a call. Used by com.android.internal.telephony.CallManager when
|
||||||
* entering and exiting calls.
|
* entering and exiting calls.
|
||||||
*/
|
*/
|
||||||
@ -539,40 +540,40 @@ public class MediaFocusControl implements OnFinished {
|
|||||||
* Helper function:
|
* Helper function:
|
||||||
* Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
|
* Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
|
||||||
* The implementation guarantees that a state where focus cannot be immediately reassigned
|
* The implementation guarantees that a state where focus cannot be immediately reassigned
|
||||||
* implies that an "exclusive" focus owner is at the top of the focus stack.
|
* implies that an "locked" focus owner is at the top of the focus stack.
|
||||||
* Modifications to the implementation that break this assumption will cause focus requests to
|
* Modifications to the implementation that break this assumption will cause focus requests to
|
||||||
* misbehave when honoring the AudioManager.AUDIOFOCUS_FLAG_DELAY_OK flag.
|
* misbehave when honoring the AudioManager.AUDIOFOCUS_FLAG_DELAY_OK flag.
|
||||||
*/
|
*/
|
||||||
private boolean canReassignAudioFocus() {
|
private boolean canReassignAudioFocus() {
|
||||||
// focus requests are rejected during a phone call or when the phone is ringing
|
// focus requests are rejected during a phone call or when the phone is ringing
|
||||||
// this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
|
// this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
|
||||||
if (!mFocusStack.isEmpty() && isExclusiveFocusOwner(mFocusStack.peek())) {
|
if (!mFocusStack.isEmpty() && isLockedFocusOwner(mFocusStack.peek())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isExclusiveFocusOwner(FocusRequester fr) {
|
private boolean isLockedFocusOwner(FocusRequester fr) {
|
||||||
return fr.hasSameClient(IN_VOICE_COMM_FOCUS_ID);
|
return (fr.hasSameClient(IN_VOICE_COMM_FOCUS_ID) || fr.isLockedFocusOwner());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function
|
* Helper function
|
||||||
* Pre-conditions: focus stack is not empty, there is one or more exclusive focus owner
|
* Pre-conditions: focus stack is not empty, there is one or more locked focus owner
|
||||||
* at the top of the focus stack
|
* at the top of the focus stack
|
||||||
* Push the focus requester onto the audio focus stack at the first position immediately
|
* Push the focus requester onto the audio focus stack at the first position immediately
|
||||||
* following the exclusive focus owners.
|
* following the locked focus owners.
|
||||||
* @return {@link AudioManager#AUDIOFOCUS_REQUEST_GRANTED} or
|
* @return {@link AudioManager#AUDIOFOCUS_REQUEST_GRANTED} or
|
||||||
* {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}
|
* {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}
|
||||||
*/
|
*/
|
||||||
private int pushBelowExclusiveFocusOwners(FocusRequester nfr) {
|
private int pushBelowLockedFocusOwners(FocusRequester nfr) {
|
||||||
int lastExclusiveFocusOwnerIndex = mFocusStack.size();
|
int lastLockedFocusOwnerIndex = mFocusStack.size();
|
||||||
for (int index = mFocusStack.size()-1; index >= 0; index--) {
|
for (int index = mFocusStack.size()-1; index >= 0; index--) {
|
||||||
if (isExclusiveFocusOwner(mFocusStack.elementAt(index))) {
|
if (isLockedFocusOwner(mFocusStack.elementAt(index))) {
|
||||||
lastExclusiveFocusOwnerIndex = index;
|
lastLockedFocusOwnerIndex = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lastExclusiveFocusOwnerIndex == mFocusStack.size()) {
|
if (lastLockedFocusOwnerIndex == mFocusStack.size()) {
|
||||||
// this should not happen, but handle it and log an error
|
// this should not happen, but handle it and log an error
|
||||||
Log.e(TAG, "No exclusive focus owner found in propagateFocusLossFromGain_syncAf()",
|
Log.e(TAG, "No exclusive focus owner found in propagateFocusLossFromGain_syncAf()",
|
||||||
new Exception());
|
new Exception());
|
||||||
@ -581,7 +582,7 @@ public class MediaFocusControl implements OnFinished {
|
|||||||
mFocusStack.push(nfr);
|
mFocusStack.push(nfr);
|
||||||
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
|
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
|
||||||
} else {
|
} else {
|
||||||
mFocusStack.insertElementAt(nfr, lastExclusiveFocusOwnerIndex);
|
mFocusStack.insertElementAt(nfr, lastLockedFocusOwnerIndex);
|
||||||
return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
|
return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -687,7 +688,7 @@ public class MediaFocusControl implements OnFinished {
|
|||||||
if (focusGrantDelayed) {
|
if (focusGrantDelayed) {
|
||||||
// focusGrantDelayed being true implies we can't reassign focus right now
|
// focusGrantDelayed being true implies we can't reassign focus right now
|
||||||
// which implies the focus stack is not empty.
|
// which implies the focus stack is not empty.
|
||||||
return pushBelowExclusiveFocusOwners(nfr);
|
return pushBelowLockedFocusOwners(nfr);
|
||||||
} else {
|
} else {
|
||||||
// propagate the focus change through the stack
|
// propagate the focus change through the stack
|
||||||
if (!mFocusStack.empty()) {
|
if (!mFocusStack.empty()) {
|
||||||
@ -703,8 +704,11 @@ public class MediaFocusControl implements OnFinished {
|
|||||||
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
|
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener) */
|
/**
|
||||||
protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) {
|
* @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener, AudioAttributes)
|
||||||
|
* */
|
||||||
|
protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId, AudioAttributes aa) {
|
||||||
|
// AudioAttributes are currently ignored, to be used for zones
|
||||||
Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId);
|
Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId);
|
||||||
try {
|
try {
|
||||||
// this will take care of notifying the new focus owner if needed
|
// this will take care of notifying the new focus owner if needed
|
||||||
|
Reference in New Issue
Block a user