Synchronous audio focus behavior with external focus policy
This patch preserves the synchronous nature of audio focus requests, even when an external focus policy is installed. When focus is requested, the request is blocked on the client-side, while AudioService informs the external policy of the request, and until the ext policy responds with the focus request result for this client, or it times out. The new AudioPolicy API is the call for the external policy to send the focus request result. Bug: 63906162 Test: gts-tradefed run gts -m GtsGmscoreHostTestCases -t 'com.google.android.gts.audio.AudioHostTest#testFocusPolicy' Change-Id: I4671517f7f00eaaed8748bd4013b7d20be3085fb
This commit is contained in:
@@ -2513,6 +2513,7 @@ package android.media {
|
||||
method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
|
||||
method public deprecated int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;
|
||||
method public int requestAudioFocus(android.media.AudioFocusRequest, android.media.audiopolicy.AudioPolicy);
|
||||
method public void setFocusRequestResult(android.media.AudioFocusInfo, int, android.media.audiopolicy.AudioPolicy);
|
||||
method public void unregisterAudioPolicyAsync(android.media.audiopolicy.AudioPolicy);
|
||||
field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
|
||||
field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
|
||||
|
||||
@@ -38,6 +38,10 @@ public final class AudioFocusInfo implements Parcelable {
|
||||
private int mLossReceived;
|
||||
private int mFlags;
|
||||
|
||||
// generation count for the validity of a request/response async exchange between
|
||||
// external focus policy and MediaFocusControl
|
||||
private long mGenCount = -1;
|
||||
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
@@ -61,6 +65,16 @@ public final class AudioFocusInfo implements Parcelable {
|
||||
mSdkTarget = sdk;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setGen(long g) {
|
||||
mGenCount = g;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public long getGen() {
|
||||
return mGenCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The audio attributes for the audio focus request.
|
||||
@@ -128,6 +142,7 @@ public final class AudioFocusInfo implements Parcelable {
|
||||
dest.writeInt(mLossReceived);
|
||||
dest.writeInt(mFlags);
|
||||
dest.writeInt(mSdkTarget);
|
||||
dest.writeLong(mGenCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -168,6 +183,8 @@ public final class AudioFocusInfo implements Parcelable {
|
||||
if (mSdkTarget != other.mSdkTarget) {
|
||||
return false;
|
||||
}
|
||||
// mGenCount is not used to verify equality between two focus holds as multiple requests
|
||||
// (hence of different generations) could correspond to the same hold
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -175,7 +192,7 @@ public final class AudioFocusInfo implements Parcelable {
|
||||
= new Parcelable.Creator<AudioFocusInfo>() {
|
||||
|
||||
public AudioFocusInfo createFromParcel(Parcel in) {
|
||||
return new AudioFocusInfo(
|
||||
final AudioFocusInfo afi = new AudioFocusInfo(
|
||||
AudioAttributes.CREATOR.createFromParcel(in), //AudioAttributes aa
|
||||
in.readInt(), // int clientUid
|
||||
in.readString(), //String clientId
|
||||
@@ -185,6 +202,8 @@ public final class AudioFocusInfo implements Parcelable {
|
||||
in.readInt(), //int flags
|
||||
in.readInt() //int sdkTarget
|
||||
);
|
||||
afi.setGen(in.readLong());
|
||||
return afi;
|
||||
}
|
||||
|
||||
public AudioFocusInfo[] newArray(int size) {
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.audiopolicy.AudioPolicy;
|
||||
import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
|
||||
import android.media.session.MediaController;
|
||||
import android.media.session.MediaSession;
|
||||
import android.media.session.MediaSessionLegacyHelper;
|
||||
@@ -54,10 +55,13 @@ import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -2338,6 +2342,20 @@ public class AudioManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
|
||||
synchronized (mFocusRequestsLock) {
|
||||
// TODO use generation counter as the key instead
|
||||
final BlockingFocusResultReceiver focusReceiver =
|
||||
mFocusRequestsAwaitingResult.remove(clientId);
|
||||
if (focusReceiver != null) {
|
||||
focusReceiver.notifyResult(requestResult);
|
||||
} else {
|
||||
Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
|
||||
@@ -2390,6 +2408,40 @@ public class AudioManager {
|
||||
*/
|
||||
public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
|
||||
AUDIOFOCUS_REQUEST_FAILED,
|
||||
AUDIOFOCUS_REQUEST_GRANTED,
|
||||
AUDIOFOCUS_REQUEST_DELAYED }
|
||||
)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface FocusRequestResult {}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* code returned when a synchronous focus request on the client-side is to be blocked
|
||||
* until the external audio focus policy decides on the response for the client
|
||||
*/
|
||||
public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
|
||||
|
||||
/**
|
||||
* Timeout duration in ms when waiting on an external focus policy for the result for a
|
||||
* focus request
|
||||
*/
|
||||
private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 200;
|
||||
|
||||
private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
|
||||
|
||||
private final Object mFocusRequestsLock = new Object();
|
||||
/**
|
||||
* Map of all receivers of focus request results, one per unresolved focus request.
|
||||
* Receivers are added before sending the request to the external focus policy,
|
||||
* and are removed either after receiving the result, or after the timeout.
|
||||
* This variable is lazily initialized.
|
||||
*/
|
||||
@GuardedBy("mFocusRequestsLock")
|
||||
private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
|
||||
|
||||
|
||||
/**
|
||||
* Request audio focus.
|
||||
@@ -2656,18 +2708,100 @@ public class AudioManager {
|
||||
// some tests don't have a Context
|
||||
sdk = Build.VERSION.SDK_INT;
|
||||
}
|
||||
try {
|
||||
status = service.requestAudioFocus(afr.getAudioAttributes(),
|
||||
afr.getFocusGain(), mICallBack,
|
||||
mAudioFocusDispatcher,
|
||||
getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()),
|
||||
getContext().getOpPackageName() /* package name */, afr.getFlags(),
|
||||
ap != null ? ap.cb() : null,
|
||||
sdk);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
|
||||
final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
|
||||
final BlockingFocusResultReceiver focusReceiver;
|
||||
synchronized (mFocusRequestsLock) {
|
||||
try {
|
||||
// TODO status contains result and generation counter for ext policy
|
||||
status = service.requestAudioFocus(afr.getAudioAttributes(),
|
||||
afr.getFocusGain(), mICallBack,
|
||||
mAudioFocusDispatcher,
|
||||
clientId,
|
||||
getContext().getOpPackageName() /* package name */, afr.getFlags(),
|
||||
ap != null ? ap.cb() : null,
|
||||
sdk);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
|
||||
// default path with no external focus policy
|
||||
return status;
|
||||
}
|
||||
if (mFocusRequestsAwaitingResult == null) {
|
||||
mFocusRequestsAwaitingResult =
|
||||
new HashMap<String, BlockingFocusResultReceiver>(1);
|
||||
}
|
||||
focusReceiver = new BlockingFocusResultReceiver(clientId);
|
||||
mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
|
||||
}
|
||||
focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
|
||||
if (DEBUG && !focusReceiver.receivedResult()) {
|
||||
Log.e(TAG, "requestAudio response from ext policy timed out, denying request");
|
||||
}
|
||||
synchronized (mFocusRequestsLock) {
|
||||
mFocusRequestsAwaitingResult.remove(clientId);
|
||||
}
|
||||
return focusReceiver.requestResult();
|
||||
}
|
||||
|
||||
// helper class that abstracts out the handling of spurious wakeups in Object.wait()
|
||||
private static final class SafeWaitObject {
|
||||
private boolean mQuit = false;
|
||||
|
||||
public void safeNotify() {
|
||||
synchronized (this) {
|
||||
mQuit = true;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public void safeWait(long millis) throws InterruptedException {
|
||||
final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
|
||||
synchronized (this) {
|
||||
while (!mQuit) {
|
||||
final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
|
||||
if (timeToWait < 0) { break; }
|
||||
this.wait(timeToWait);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class BlockingFocusResultReceiver {
|
||||
private final SafeWaitObject mLock = new SafeWaitObject();
|
||||
@GuardedBy("mLock")
|
||||
private boolean mResultReceived = false;
|
||||
// request denied by default (e.g. timeout)
|
||||
private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||
private final String mFocusClientId;
|
||||
|
||||
BlockingFocusResultReceiver(String clientId) {
|
||||
mFocusClientId = clientId;
|
||||
}
|
||||
|
||||
boolean receivedResult() { return mResultReceived; }
|
||||
int requestResult() { return mFocusRequestResult; }
|
||||
|
||||
void notifyResult(int requestResult) {
|
||||
synchronized (mLock) {
|
||||
mResultReceived = true;
|
||||
mFocusRequestResult = requestResult;
|
||||
mLock.safeNotify();
|
||||
}
|
||||
}
|
||||
|
||||
public void waitForResult(long timeOutMs) {
|
||||
synchronized (mLock) {
|
||||
if (mResultReceived) {
|
||||
// the result was received before waiting
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mLock.safeWait(timeOutMs);
|
||||
} catch (InterruptedException e) { }
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2712,6 +2846,32 @@ public class AudioManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Set the result to the audio focus request received through
|
||||
* {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
|
||||
* @param afi the information about the focus requester
|
||||
* @param requestResult the result to the focus request to be passed to the requester
|
||||
* @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||
public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
|
||||
@FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
|
||||
if (afi == null) {
|
||||
throw new IllegalArgumentException("Illegal null AudioFocusInfo");
|
||||
}
|
||||
if (ap == null) {
|
||||
throw new IllegalArgumentException("Illegal null AudioPolicy");
|
||||
}
|
||||
final IAudioService service = getService();
|
||||
try {
|
||||
service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Notifies an application with a focus listener of gain or loss of audio focus.
|
||||
|
||||
@@ -25,4 +25,6 @@ oneway interface IAudioFocusDispatcher {
|
||||
|
||||
void dispatchAudioFocusChange(int focusChange, String clientId);
|
||||
|
||||
void dispatchFocusResultFromExtPolicy(int requestResult, String clientId);
|
||||
|
||||
}
|
||||
|
||||
@@ -207,5 +207,8 @@ interface IAudioService {
|
||||
int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
|
||||
int state, int profile, boolean suppressNoisyIntent);
|
||||
|
||||
oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult,
|
||||
in IAudioPolicyCallback pcb);
|
||||
|
||||
// WARNING: read warning at top of file, it is recommended to add new methods at the end
|
||||
}
|
||||
|
||||
@@ -463,9 +463,9 @@ public class AudioPolicy {
|
||||
* Only ever called if the {@link AudioPolicy} was built with
|
||||
* {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to {@code true}.
|
||||
* @param afi information about the focus request and the requester
|
||||
* @param requestResult the result that was returned synchronously by the framework to the
|
||||
* application, {@link #AUDIOFOCUS_REQUEST_FAILED},or
|
||||
* {@link #AUDIOFOCUS_REQUEST_DELAYED}.
|
||||
* @param requestResult deprecated after the addition of
|
||||
* {@link AudioManager#setFocusRequestResult(AudioFocusInfo, int, AudioPolicy)}
|
||||
* in Android P, always equal to {@link #AUDIOFOCUS_REQUEST_GRANTED}.
|
||||
*/
|
||||
public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {}
|
||||
/**
|
||||
@@ -534,7 +534,7 @@ public class AudioPolicy {
|
||||
sendMsg(MSG_FOCUS_REQUEST, afi, requestResult);
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, "notifyAudioFocusRequest: pack=" + afi.getPackageName() + " client="
|
||||
+ afi.getClientId() + "reqRes=" + requestResult);
|
||||
+ afi.getClientId() + " gen=" + afi.getGen());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7296,6 +7296,12 @@ public class AudioService extends IAudioService.Stub
|
||||
//======================
|
||||
/** */
|
||||
public int dispatchFocusChange(AudioFocusInfo afi, int focusChange, IAudioPolicyCallback pcb) {
|
||||
if (afi == null) {
|
||||
throw new IllegalArgumentException("Illegal null AudioFocusInfo");
|
||||
}
|
||||
if (pcb == null) {
|
||||
throw new IllegalArgumentException("Illegal null AudioPolicy callback");
|
||||
}
|
||||
synchronized (mAudioPolicies) {
|
||||
if (!mAudioPolicies.containsKey(pcb.asBinder())) {
|
||||
throw new IllegalStateException("Unregistered AudioPolicy for focus dispatch");
|
||||
@@ -7304,6 +7310,23 @@ public class AudioService extends IAudioService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
public void setFocusRequestResultFromExtPolicy(AudioFocusInfo afi, int requestResult,
|
||||
IAudioPolicyCallback pcb) {
|
||||
if (afi == null) {
|
||||
throw new IllegalArgumentException("Illegal null AudioFocusInfo");
|
||||
}
|
||||
if (pcb == null) {
|
||||
throw new IllegalArgumentException("Illegal null AudioPolicy callback");
|
||||
}
|
||||
synchronized (mAudioPolicies) {
|
||||
if (!mAudioPolicies.containsKey(pcb.asBinder())) {
|
||||
throw new IllegalStateException("Unregistered AudioPolicy for external focus");
|
||||
}
|
||||
mMediaFocusControl.setFocusRequestResultFromExtPolicy(afi, requestResult);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//======================
|
||||
// misc
|
||||
//======================
|
||||
|
||||
@@ -241,15 +241,15 @@ public class FocusRequester {
|
||||
|
||||
|
||||
void release() {
|
||||
final IBinder srcRef = mSourceRef;
|
||||
final AudioFocusDeathHandler deathHdlr = mDeathHandler;
|
||||
try {
|
||||
if (mSourceRef != null && mDeathHandler != null) {
|
||||
mSourceRef.unlinkToDeath(mDeathHandler, 0);
|
||||
mDeathHandler = null;
|
||||
mFocusDispatcher = null;
|
||||
if (srcRef != null && deathHdlr != null) {
|
||||
srcRef.unlinkToDeath(deathHdlr, 0);
|
||||
}
|
||||
} catch (java.util.NoSuchElementException e) {
|
||||
Log.e(TAG, "FocusRequester.release() hit ", e);
|
||||
}
|
||||
} catch (java.util.NoSuchElementException e) { }
|
||||
mDeathHandler = null;
|
||||
mFocusDispatcher = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -424,7 +424,7 @@ public class FocusRequester {
|
||||
|
||||
int dispatchFocusChange(int focusChange) {
|
||||
if (mFocusDispatcher == null) {
|
||||
if (MediaFocusControl.DEBUG) { Log.v(TAG, "dispatchFocusChange: no focus dispatcher"); }
|
||||
if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusChange: no focus dispatcher"); }
|
||||
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||
}
|
||||
if (focusChange == AudioManager.AUDIOFOCUS_NONE) {
|
||||
@@ -445,12 +445,29 @@ public class FocusRequester {
|
||||
try {
|
||||
mFocusDispatcher.dispatchAudioFocusChange(focusChange, mClientId);
|
||||
} catch (android.os.RemoteException e) {
|
||||
Log.v(TAG, "dispatchFocusChange: error talking to focus listener", e);
|
||||
Log.e(TAG, "dispatchFocusChange: error talking to focus listener " + mClientId, e);
|
||||
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||
}
|
||||
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
|
||||
}
|
||||
|
||||
void dispatchFocusResultFromExtPolicy(int requestResult) {
|
||||
if (mFocusDispatcher == null) {
|
||||
if (MediaFocusControl.DEBUG) {
|
||||
Log.e(TAG, "dispatchFocusResultFromExtPolicy: no focus dispatcher");
|
||||
}
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, "dispatching result" + requestResult + " to " + mClientId);
|
||||
}
|
||||
try {
|
||||
mFocusDispatcher.dispatchFocusResultFromExtPolicy(requestResult, mClientId);
|
||||
} catch (android.os.RemoteException e) {
|
||||
Log.e(TAG, "dispatchFocusResultFromExtPolicy: error talking to focus listener"
|
||||
+ mClientId, e);
|
||||
}
|
||||
}
|
||||
|
||||
AudioFocusInfo toAudioFocusInfo() {
|
||||
return new AudioFocusInfo(mAttributes, mCallingUid, mClientId, mPackageName,
|
||||
mFocusGainRequest, mFocusLossReceived, mGrantFlags, mSdkTarget);
|
||||
|
||||
@@ -83,6 +83,10 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
|
||||
private boolean mRingOrCallActive = false;
|
||||
|
||||
private final Object mExtFocusChangeLock = new Object();
|
||||
@GuardedBy("mExtFocusChangeLock")
|
||||
private long mExtFocusChangeCounter;
|
||||
|
||||
protected MediaFocusControl(Context cntxt, PlayerFocusEnforcer pfe) {
|
||||
mContext = cntxt;
|
||||
mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
|
||||
@@ -521,7 +525,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
* @param requestResult
|
||||
* @return true if the external audio focus policy (if any) is handling the focus request
|
||||
*/
|
||||
boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi, int requestResult,
|
||||
boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi,
|
||||
IAudioFocusDispatcher fd, IBinder cb) {
|
||||
if (mFocusPolicy == null) {
|
||||
return false;
|
||||
@@ -530,6 +534,9 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
Log.v(TAG, "notifyExtFocusPolicyFocusRequest client="+afi.getClientId()
|
||||
+ " dispatcher=" + fd);
|
||||
}
|
||||
synchronized (mExtFocusChangeLock) {
|
||||
afi.setGen(mExtFocusChangeCounter++);
|
||||
}
|
||||
final FocusRequester existingFr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
|
||||
if (existingFr != null) {
|
||||
if (!existingFr.hasSameDispatcher(fd)) {
|
||||
@@ -538,8 +545,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
mFocusOwnersForFocusPolicy.put(afi.getClientId(),
|
||||
new FocusRequester(afi, fd, cb, hdlr, this));
|
||||
}
|
||||
} else if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
|
||||
|| requestResult == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
|
||||
} else {
|
||||
// new focus (future) focus owner to keep track of
|
||||
final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
|
||||
mFocusOwnersForFocusPolicy.put(afi.getClientId(),
|
||||
@@ -547,12 +553,25 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
}
|
||||
try {
|
||||
//oneway
|
||||
mFocusPolicy.notifyAudioFocusRequest(afi, requestResult);
|
||||
mFocusPolicy.notifyAudioFocusRequest(afi, AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Can't call notifyAudioFocusRequest() on IAudioPolicyCallback "
|
||||
+ mFocusPolicy.asBinder(), e);
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void setFocusRequestResultFromExtPolicy(AudioFocusInfo afi, int requestResult) {
|
||||
synchronized (mExtFocusChangeLock) {
|
||||
if (afi.getGen() > mExtFocusChangeCounter) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
final FocusRequester fr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
|
||||
if (fr != null) {
|
||||
fr.dispatchFocusResultFromExtPolicy(requestResult);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -590,7 +609,12 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
if (DEBUG) { Log.v(TAG, "> failed: no focus policy" ); }
|
||||
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||
}
|
||||
final FocusRequester fr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
|
||||
final FocusRequester fr;
|
||||
if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
|
||||
fr = mFocusOwnersForFocusPolicy.remove(afi.getClientId());
|
||||
} else {
|
||||
fr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
|
||||
}
|
||||
if (fr == null) {
|
||||
if (DEBUG) { Log.v(TAG, "> failed: no such focus requester known" ); }
|
||||
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||
@@ -710,9 +734,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
boolean focusGrantDelayed = false;
|
||||
if (!canReassignAudioFocus()) {
|
||||
if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) {
|
||||
final int result = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||
notifyExtFocusPolicyFocusRequest_syncAf(afiForExtPolicy, result, fd, cb);
|
||||
return result;
|
||||
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
|
||||
@@ -721,12 +743,11 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
|
||||
}
|
||||
}
|
||||
|
||||
// external focus policy: delay request for focus gain?
|
||||
final int resultWithExtPolicy = AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
|
||||
// external focus policy?
|
||||
if (notifyExtFocusPolicyFocusRequest_syncAf(
|
||||
afiForExtPolicy, resultWithExtPolicy, fd, cb)) {
|
||||
afiForExtPolicy, fd, cb)) {
|
||||
// stop handling focus request here as it is handled by external audio focus policy
|
||||
return resultWithExtPolicy;
|
||||
return AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY;
|
||||
}
|
||||
|
||||
// handle the potential premature death of the new holder of the focus
|
||||
|
||||
Reference in New Issue
Block a user