Merge "Support for delayed audio focus" into lmp-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
136f54153e
@ -2201,6 +2201,8 @@ public class AudioManager {
|
|||||||
listener = findFocusListener((String)msg.obj);
|
listener = findFocusListener((String)msg.obj);
|
||||||
}
|
}
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
|
Log.d(TAG, "AudioManager dispatching onAudioFocusChange("
|
||||||
|
+ msg.what + ") for " + msg.obj);
|
||||||
listener.onAudioFocusChange(msg.what);
|
listener.onAudioFocusChange(msg.what);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2270,6 +2272,14 @@ public class AudioManager {
|
|||||||
* A successful focus change request.
|
* A successful focus change request.
|
||||||
*/
|
*/
|
||||||
public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
|
public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* A focus change request whose granting is delayed: the request was successful, but the
|
||||||
|
* requester will only be granted audio focus once the condition that prevented immediate
|
||||||
|
* granting has ended.
|
||||||
|
* See {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
|
||||||
|
*/
|
||||||
|
public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2291,18 +2301,87 @@ public class AudioManager {
|
|||||||
*/
|
*/
|
||||||
public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
|
public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
|
||||||
int status = AUDIOFOCUS_REQUEST_FAILED;
|
int status = AUDIOFOCUS_REQUEST_FAILED;
|
||||||
if ((durationHint < AUDIOFOCUS_GAIN) ||
|
|
||||||
(durationHint > AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
|
try {
|
||||||
Log.e(TAG, "Invalid duration hint, audio focus request denied");
|
// status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
|
||||||
|
// AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
|
||||||
|
// AUDIOFOCUS_FLAG_DELAY_OK flag
|
||||||
|
status = requestAudioFocus(l,
|
||||||
|
new AudioAttributes.Builder()
|
||||||
|
.setInternalLegacyStreamType(streamType).build(),
|
||||||
|
durationHint,
|
||||||
|
0 /* flags, legacy behavior */);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.e(TAG, "Audio focus request denied due to ", e);
|
||||||
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// when adding new flags, add them to AUDIOFOCUS_FLAGS_ALL
|
||||||
|
/** @hide */
|
||||||
|
public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
|
||||||
|
/** @hide */
|
||||||
|
public static final int AUDIOFOCUS_FLAGS_ALL = AUDIOFOCUS_FLAG_DELAY_OK;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* @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}.
|
||||||
|
* @param requestAttributes non null {@link AudioAttributes} describing the main reason for
|
||||||
|
* requesting audio focus.
|
||||||
|
* @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
|
||||||
|
* is temporary, and focus will be abandonned shortly. Examples of transient requests are
|
||||||
|
* for the playback of driving directions, or notifications sounds.
|
||||||
|
* Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
|
||||||
|
* the previous focus owner to keep playing if it ducks its audio output.
|
||||||
|
* Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
|
||||||
|
* that benefits from the system not playing disruptive sounds like notifications, for
|
||||||
|
* usecases such as voice memo recording, or speech recognition.
|
||||||
|
* Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
|
||||||
|
* as the playback of a song or a video.
|
||||||
|
* @param flags 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).
|
||||||
|
* 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.
|
||||||
|
* @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
|
||||||
|
* or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
|
||||||
|
* The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
|
||||||
|
* without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
*/
|
||||||
|
public int requestAudioFocus(OnAudioFocusChangeListener l,
|
||||||
|
AudioAttributes requestAttributes,
|
||||||
|
int durationHint,
|
||||||
|
int flags) throws IllegalArgumentException {
|
||||||
|
// parameter checking
|
||||||
|
if (requestAttributes == null) {
|
||||||
|
throw new IllegalArgumentException("Illegal null AudioAttributes argument");
|
||||||
|
}
|
||||||
|
if ((durationHint < AUDIOFOCUS_GAIN) ||
|
||||||
|
(durationHint > AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
|
||||||
|
throw new IllegalArgumentException("Invalid duration hint");
|
||||||
|
}
|
||||||
|
if (flags != (flags & AUDIOFOCUS_FLAGS_ALL)) {
|
||||||
|
throw new IllegalArgumentException("Illegal flags 0x"
|
||||||
|
+ Integer.toHexString(flags).toUpperCase());
|
||||||
|
}
|
||||||
|
if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Illegal null focus listener when flagged as accepting delayed focus grant");
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = AUDIOFOCUS_REQUEST_FAILED;
|
||||||
registerAudioFocusListener(l);
|
registerAudioFocusListener(l);
|
||||||
//TODO protect request by permission check?
|
|
||||||
IAudioService service = getService();
|
IAudioService service = getService();
|
||||||
try {
|
try {
|
||||||
status = service.requestAudioFocus(streamType, durationHint, mICallBack,
|
status = service.requestAudioFocus(requestAttributes, durationHint, mICallBack,
|
||||||
mAudioFocusDispatcher, getIdForAudioFocusListener(l),
|
mAudioFocusDispatcher, getIdForAudioFocusListener(l),
|
||||||
mContext.getOpPackageName() /* package name */);
|
mContext.getOpPackageName() /* package name */, flags);
|
||||||
} 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 due to "+e);
|
||||||
}
|
}
|
||||||
@ -2322,9 +2401,11 @@ public class AudioManager {
|
|||||||
public void requestAudioFocusForCall(int streamType, int durationHint) {
|
public void requestAudioFocusForCall(int streamType, int durationHint) {
|
||||||
IAudioService service = getService();
|
IAudioService service = getService();
|
||||||
try {
|
try {
|
||||||
service.requestAudioFocus(streamType, durationHint, mICallBack, null,
|
service.requestAudioFocus(new AudioAttributes.Builder()
|
||||||
|
.setInternalLegacyStreamType(streamType).build(),
|
||||||
|
durationHint, mICallBack, null,
|
||||||
MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
|
MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
|
||||||
mContext.getOpPackageName());
|
mContext.getOpPackageName(), 0 /* flags, legacy behavior*/ );
|
||||||
} 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 due to "+e);
|
||||||
}
|
}
|
||||||
|
@ -5011,10 +5011,10 @@ public class AudioService extends IAudioService.Stub {
|
|||||||
//==========================================================================================
|
//==========================================================================================
|
||||||
// Audio Focus
|
// Audio Focus
|
||||||
//==========================================================================================
|
//==========================================================================================
|
||||||
public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
|
public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
|
||||||
IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
|
IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags) {
|
||||||
return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
|
return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
|
||||||
clientId, callingPackageName);
|
clientId, callingPackageName, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
|
public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
|
||||||
|
@ -44,20 +44,25 @@ class FocusRequester {
|
|||||||
* the audio focus gain request that caused the addition of this object in the focus stack.
|
* the audio focus gain request that caused the addition of this object in the focus stack.
|
||||||
*/
|
*/
|
||||||
private final int mFocusGainRequest;
|
private final int mFocusGainRequest;
|
||||||
|
/**
|
||||||
|
* the flags associated with the gain request that qualify the type of grant (e.g. accepting
|
||||||
|
* delay vs grant must be immediate)
|
||||||
|
*/
|
||||||
|
private final int mGrantFlags;
|
||||||
/**
|
/**
|
||||||
* the audio focus loss received my mFocusDispatcher, is AudioManager.AUDIOFOCUS_NONE if
|
* the audio focus loss received my mFocusDispatcher, is AudioManager.AUDIOFOCUS_NONE if
|
||||||
* it never lost focus.
|
* it never lost focus.
|
||||||
*/
|
*/
|
||||||
private int mFocusLossReceived;
|
private int mFocusLossReceived;
|
||||||
/**
|
/**
|
||||||
* the stream type associated with the focus request
|
* the audio attributes associated with the focus request
|
||||||
*/
|
*/
|
||||||
private final int mStreamType;
|
private final AudioAttributes mAttributes;
|
||||||
|
|
||||||
FocusRequester(int streamType, int focusRequest,
|
FocusRequester(AudioAttributes aa, int focusRequest, int grantFlags,
|
||||||
IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
|
IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
|
||||||
String pn, int uid) {
|
String pn, int uid) {
|
||||||
mStreamType = streamType;
|
mAttributes = aa;
|
||||||
mFocusDispatcher = afl;
|
mFocusDispatcher = afl;
|
||||||
mSourceRef = source;
|
mSourceRef = source;
|
||||||
mClientId = id;
|
mClientId = id;
|
||||||
@ -65,6 +70,7 @@ class FocusRequester {
|
|||||||
mPackageName = pn;
|
mPackageName = pn;
|
||||||
mCallingUid = uid;
|
mCallingUid = uid;
|
||||||
mFocusGainRequest = focusRequest;
|
mFocusGainRequest = focusRequest;
|
||||||
|
mGrantFlags = grantFlags;
|
||||||
mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
|
mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,8 +104,12 @@ class FocusRequester {
|
|||||||
return mFocusGainRequest;
|
return mFocusGainRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getStreamType() {
|
int getGrantFlags() {
|
||||||
return mStreamType;
|
return mGrantFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioAttributes getAudioAttributes() {
|
||||||
|
return mAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -139,9 +149,10 @@ class FocusRequester {
|
|||||||
+ " -- pack: " + mPackageName
|
+ " -- pack: " + mPackageName
|
||||||
+ " -- client: " + mClientId
|
+ " -- client: " + mClientId
|
||||||
+ " -- gain: " + focusGainToString()
|
+ " -- gain: " + focusGainToString()
|
||||||
|
+ " -- grant: " + mGrantFlags
|
||||||
+ " -- loss: " + focusLossToString()
|
+ " -- loss: " + focusLossToString()
|
||||||
+ " -- uid: " + mCallingUid
|
+ " -- uid: " + mCallingUid
|
||||||
+ " -- stream: " + mStreamType);
|
+ " -- attr: " + mAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ package android.media;
|
|||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
|
import android.media.AudioAttributes;
|
||||||
import android.media.AudioRoutesInfo;
|
import android.media.AudioRoutesInfo;
|
||||||
import android.media.IAudioFocusDispatcher;
|
import android.media.IAudioFocusDispatcher;
|
||||||
import android.media.IAudioRoutesObserver;
|
import android.media.IAudioRoutesObserver;
|
||||||
@ -116,8 +117,8 @@ interface IAudioService {
|
|||||||
|
|
||||||
boolean isBluetoothA2dpOn();
|
boolean isBluetoothA2dpOn();
|
||||||
|
|
||||||
int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
|
int requestAudioFocus(in AudioAttributes aa, int durationHint, IBinder cb,
|
||||||
IAudioFocusDispatcher fd, String clientId, String callingPackageName);
|
IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags);
|
||||||
|
|
||||||
int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId);
|
int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId);
|
||||||
|
|
||||||
|
@ -538,16 +538,54 @@ 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
|
||||||
|
* implies that an "exclusive" focus owner is at the top of the focus stack.
|
||||||
|
* Modifications to the implementation that break this assumption will cause focus requests to
|
||||||
|
* 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() && mFocusStack.peek().hasSameClient(IN_VOICE_COMM_FOCUS_ID)) {
|
if (!mFocusStack.isEmpty() && isExclusiveFocusOwner(mFocusStack.peek())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isExclusiveFocusOwner(FocusRequester fr) {
|
||||||
|
return fr.hasSameClient(IN_VOICE_COMM_FOCUS_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function
|
||||||
|
* Pre-conditions: focus stack is not empty, there is one or more exclusive focus owner
|
||||||
|
* at the top of the focus stack
|
||||||
|
* Push the focus requester onto the audio focus stack at the first position immediately
|
||||||
|
* following the exclusive focus owners.
|
||||||
|
* @return {@link AudioManager#AUDIOFOCUS_REQUEST_GRANTED} or
|
||||||
|
* {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}
|
||||||
|
*/
|
||||||
|
private int pushBelowExclusiveFocusOwners(FocusRequester nfr) {
|
||||||
|
int lastExclusiveFocusOwnerIndex = mFocusStack.size();
|
||||||
|
for (int index = mFocusStack.size()-1; index >= 0; index--) {
|
||||||
|
if (isExclusiveFocusOwner(mFocusStack.elementAt(index))) {
|
||||||
|
lastExclusiveFocusOwnerIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastExclusiveFocusOwnerIndex == mFocusStack.size()) {
|
||||||
|
// this should not happen, but handle it and log an error
|
||||||
|
Log.e(TAG, "No exclusive focus owner found in propagateFocusLossFromGain_syncAf()",
|
||||||
|
new Exception());
|
||||||
|
// no exclusive owner, push at top of stack, focus is granted, propagate change
|
||||||
|
propagateFocusLossFromGain_syncAf(nfr.getGainRequest());
|
||||||
|
mFocusStack.push(nfr);
|
||||||
|
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
|
||||||
|
} else {
|
||||||
|
mFocusStack.insertElementAt(nfr, lastExclusiveFocusOwnerIndex);
|
||||||
|
return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inner class to monitor audio focus client deaths, and remove them from the audio focus
|
* Inner class to monitor audio focus client deaths, and remove them from the audio focus
|
||||||
* stack if necessary.
|
* stack if necessary.
|
||||||
@ -581,10 +619,11 @@ public class MediaFocusControl implements OnFinished {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int) */
|
/** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */
|
||||||
protected int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
|
protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb,
|
||||||
IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
|
IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags) {
|
||||||
Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId);
|
Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId + " req=" + focusChangeHint +
|
||||||
|
"flags=0x" + Integer.toHexString(flags));
|
||||||
// we need a valid binder callback for clients
|
// we need a valid binder callback for clients
|
||||||
if (!cb.pingBinder()) {
|
if (!cb.pingBinder()) {
|
||||||
Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
|
Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
|
||||||
@ -597,8 +636,16 @@ public class MediaFocusControl implements OnFinished {
|
|||||||
}
|
}
|
||||||
|
|
||||||
synchronized(mAudioFocusLock) {
|
synchronized(mAudioFocusLock) {
|
||||||
|
boolean focusGrantDelayed = false;
|
||||||
if (!canReassignAudioFocus()) {
|
if (!canReassignAudioFocus()) {
|
||||||
|
if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) {
|
||||||
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||||
|
} else {
|
||||||
|
// request has AUDIOFOCUS_FLAG_DELAY_OK: focus can't be
|
||||||
|
// granted right now, so the requester will be inserted in the focus stack
|
||||||
|
// to receive focus later
|
||||||
|
focusGrantDelayed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle the potential premature death of the new holder of the focus
|
// handle the potential premature death of the new holder of the focus
|
||||||
@ -616,7 +663,8 @@ public class MediaFocusControl implements OnFinished {
|
|||||||
if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
|
if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
|
||||||
// if focus is already owned by this client and the reason for acquiring the focus
|
// if focus is already owned by this client and the reason for acquiring the focus
|
||||||
// hasn't changed, don't do anything
|
// hasn't changed, don't do anything
|
||||||
if (mFocusStack.peek().getGainRequest() == focusChangeHint) {
|
final FocusRequester fr = mFocusStack.peek();
|
||||||
|
if (fr.getGainRequest() == focusChangeHint && fr.getGrantFlags() == flags) {
|
||||||
// unlink death handler so it can be gc'ed.
|
// unlink death handler so it can be gc'ed.
|
||||||
// linkToDeath() creates a JNI global reference preventing collection.
|
// linkToDeath() creates a JNI global reference preventing collection.
|
||||||
cb.unlinkToDeath(afdh, 0);
|
cb.unlinkToDeath(afdh, 0);
|
||||||
@ -624,21 +672,31 @@ public class MediaFocusControl implements OnFinished {
|
|||||||
}
|
}
|
||||||
// the reason for the audio focus request has changed: remove the current top of
|
// the reason for the audio focus request has changed: remove the current top of
|
||||||
// stack and respond as if we had a new focus owner
|
// stack and respond as if we had a new focus owner
|
||||||
FocusRequester fr = mFocusStack.pop();
|
if (!focusGrantDelayed) {
|
||||||
|
mFocusStack.pop();
|
||||||
|
// the entry that was "popped" is the same that was "peeked" above
|
||||||
fr.release();
|
fr.release();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// focus requester might already be somewhere below in the stack, remove it
|
// focus requester might already be somewhere below in the stack, remove it
|
||||||
removeFocusStackEntry(clientId, false /* signal */);
|
removeFocusStackEntry(clientId, false /* signal */);
|
||||||
|
|
||||||
|
final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb,
|
||||||
|
clientId, afdh, callingPackageName, Binder.getCallingUid());
|
||||||
|
if (focusGrantDelayed) {
|
||||||
|
// focusGrantDelayed being true implies we can't reassign focus right now
|
||||||
|
// which implies the focus stack is not empty.
|
||||||
|
return pushBelowExclusiveFocusOwners(nfr);
|
||||||
|
} else {
|
||||||
// propagate the focus change through the stack
|
// propagate the focus change through the stack
|
||||||
if (!mFocusStack.empty()) {
|
if (!mFocusStack.empty()) {
|
||||||
propagateFocusLossFromGain_syncAf(focusChangeHint);
|
propagateFocusLossFromGain_syncAf(focusChangeHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
// push focus requester at the top of the audio focus stack
|
// push focus requester at the top of the audio focus stack
|
||||||
mFocusStack.push(new FocusRequester(mainStreamType, focusChangeHint, fd, cb,
|
mFocusStack.push(nfr);
|
||||||
clientId, afdh, callingPackageName, Binder.getCallingUid()));
|
}
|
||||||
|
|
||||||
}//synchronized(mAudioFocusLock)
|
}//synchronized(mAudioFocusLock)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user