首先看AudioManager的requestAudioFocus方法:
//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
PlayerBase.deprecateStreamTypeForPlayback(streamType,
"AudioManager", "requestAudioFocus()");
int status = AUDIOFOCUS_REQUEST_FAILED;
try {
// 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 */); 调用requestAudioFocus的重载方法(4个参数)
} catch (IllegalArgumentException e) {
Log.e(TAG, "Audio focus request denied due to ", e);
}
return status;
}
}
调用requestAudioFocus的重载方法(4个参数):
//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
public int requestAudioFocus(OnAudioFocusChangeListener l,
@NonNull AudioAttributes requestAttributes,
int durationHint,
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*/); //继续调用重载方法(5个参数)
}
}
继续调用重载方法(5个参数):
//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
public int requestAudioFocus(OnAudioFocusChangeListener l,
@NonNull AudioAttributes requestAttributes,
int durationHint,
int flags,
AudioPolicy ap) throws IllegalArgumentException {
// parameter checking
if (requestAttributes == null) {
throw new IllegalArgumentException("Illegal null AudioAttributes argument");
}
if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
throw new IllegalArgumentException("Invalid duration hint");
}
if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
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");
}
if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
== AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) {
throw new IllegalArgumentException(
"Illegal null focus listener when flagged as pausing instead of ducking");
}
if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
throw new IllegalArgumentException(
"Illegal null audio policy when locking audio focus");
}
final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint)
.setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */)
.setAudioAttributes(requestAttributes)
.setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK)
== AUDIOFOCUS_FLAG_DELAY_OK)
.setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
== AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
.setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK)
.build(); //创建AudioFocusRequest对象,并设置参数
return requestAudioFocus(afr, ap); //继续调用重载方法(2个参数)
}
}
继续调用重载方法(2个参数):
//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
if (afr == null) {
throw new NullPointerException("Illegal null AudioFocusRequest");
}
// this can only be checked now, not during the creation of the AudioFocusRequest instance
// 我们如果设置afr的locksFocus为ture时,需要指定ap,否则就抛异常,因为目前的版本lockfocus与audiopolicy是一起使用的因此这里做了这个判断
if (afr.locksFocus() && ap == null) {
throw new IllegalArgumentException(
"Illegal null audio policy when locking audio focus");
}
//(1)注册要在音频焦点更改时调用的侦听器,并跟踪关联的焦点请求(包括用于侦听器的处理程序)
registerAudioFocusRequest(afr);
final IAudioService service = getService();
final int status;
int sdk;
try {
sdk = getContext().getApplicationInfo().targetSdkVersion;
} catch (NullPointerException e) {
// some tests don't have a Context
sdk = Build.VERSION.SDK_INT;
}
// (2)clientId 就是把我们传入的AudioFocusRequest里的listener转成了String
final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
final BlockingFocusResultReceiver focusReceiver;
synchronized (mFocusRequestsLock) {
try {
// TODO status contains result and generation counter for ext policy
//(3) 调用到了AudioService中requestAudioFocus
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();
}
// 上面说过了,目前Audio支持外部处理AudioFocus,这里判断如果不使用外部处理,则直接返回Android原生的申请焦点的结果。
if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
// default path with no external focus policy
return status;
}
// 如果map为null,则new 1个size为1的map,这个主要也是处理外部音频焦点策略的
if (mFocusRequestsAwaitingResult == null) {
mFocusRequestsAwaitingResult =
new HashMap<String, BlockingFocusResultReceiver>(1);
}
//(4)关于音频焦点拿到外部处理这块不是一句两句说的明白的,后续在分析
focusReceiver = new BlockingFocusResultReceiver(clientId);
mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
}
// 等待200ms
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();
}
......
}
以上代码逻辑比较长,简单说下几个步骤:
-
参数的校验
-
注册要在音频焦点更改时调用的侦听器,并跟踪关联的焦点请求
-
调用AudioService的requestAudioFocus
-
判断是否有外部的audiopolicy,如果没有直接返回申请结果,如果有则等外外部音频焦点处理结果
registerAudioFocusRequest
其中步骤2的代码如下:
//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
......
private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap =
new ConcurrentHashMap<String, FocusRequestInfo>();
......
private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
if (l == null) {
return new String(this.toString());
} else {
return new String(this.toString() + l.toString());
}
}
public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
final Handler h = afr.getOnAudioFocusChangeListenerHandler(); //获取音频焦点变更监听器的Handler
final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
new ServiceEventHandlerDelegate(h).getHandler()); //创建音频焦点请求Info
final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()); //获取监听器对应的key
mAudioFocusIdListenerMap.put(key, fri); //将音频焦点请求Info和监听器对应的key放入HashMap
}
......
}
AudioService.requestAudioFocus
其中步骤3的代码如下:
//frameworks/base/service/java/com/android/server/audio/AudioService.java
public class AudioService extends IAudioService.Stub
implements AccessibilityManager.TouchExplorationStateChangeListener,
AccessibilityManager.AccessibilityServicesStateChangeListener {
......
private final MediaFocusControl mMediaFocusControl;
......
public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
IAudioPolicyCallback pcb, int sdk) {
// permission checks
if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
if (AudioSystem.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(pcb.asBinder())) {
Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
}
}
}
if (callingPackageName == null || clientId == null || aa == null) {
Log.e(TAG, "Invalid null parameter to request audio focus");
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
clientId, callingPackageName, flags, sdk,
forceFocusDuckingForAccessibility(aa, durationHint, Binder.getCallingUid()));
}
......
}
大体也是分了三步
-
flag的检查,我们刚分析AudioManager的requestAudioFocus时已经看到了flag与audiopolicy的绑定判断,只不过到service又判断了一次,并详细说明了为何之前要绑定判断的原因,因为flag是lock的时候,如果不给电话用只能使用外部audiopolicy,所以之前要做与的判断。如果flag是lock状态并且给电话使用的话,那么我们就要使用requestAudioFocusForCall来申请。
-
参数判空的检查
-
调用了MediaFocusControl的requestAudioFocus
MediaFocusControl.requestAudioFocus
其中步骤3的代码如下:
public class MediaFocusControl implements PlayerFocusEnforcer {
......
protected int requestAudioFocus(@NonNull AudioAttributes aa, int focusChangeHint, IBinder cb,
IAudioFocusDispatcher fd, @NonNull String clientId, @NonNull String callingPackageName,
int flags, int sdk, boolean forceDuck) {
mEventLogger.log((new AudioEventLogger.StringEvent(
"requestAudioFocus() from uid/pid " + Binder.getCallingUid()
+ "/" + Binder.getCallingPid()
+ " clientId=" + clientId + " callingPack=" + callingPackageName
+ " req=" + focusChangeHint
+ " flags=0x" + Integer.toHexString(flags)
+ " sdk=" + sdk))
.printLog(TAG));
// we need a valid binder callback for clients
if (!cb.pingBinder()) {
Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
callingPackageName) != AppOpsManager.MODE_ALLOWED) {
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
synchronized(mAudioFocusLock) {
//其实申请成功的焦点都放到栈里维护起来了,那么这个焦点栈最多可存100个音频焦点的信息
if (mFocusStack.size() > MAX_STACK_SIZE) {
Log.e(TAG, "Max AudioFocus stack size reached, failing requestAudioFocus()");
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
boolean enteringRingOrCall = !mRingOrCallActive
& (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0);
if (enteringRingOrCall) { mRingOrCallActive = true; }
final AudioFocusInfo afiForExtPolicy;
//假设我们不使用外部audiopolicy,只是用android原生的焦点策略,这个过
if (mFocusPolicy != null) {
// construct AudioFocusInfo as it will be communicated to audio focus policy
afiForExtPolicy = new AudioFocusInfo(aa, Binder.getCallingUid(),
clientId, callingPackageName, focusChangeHint, 0 /*lossReceived*/,
flags, sdk);
} else {
afiForExtPolicy = null;
}
// handle delayed focus
boolean focusGrantDelayed = false;
// 如果当前是电话,我们申请的又不是一个可以delay的焦点,那么直接返回申请失败,如果申请的是delay的,则更新delay的flag为true
if (!canReassignAudioFocus()) {
if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) {
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;
}
}
// external focus policy?
if (mFocusPolicy != null) {
if (notifyExtFocusPolicyFocusRequest_syncAf(afiForExtPolicy, fd, cb)) { //如果是外部音频焦点策略,通过AudioPolicy.AudioPolicyFocusListener调用到CarZonesAudioFocus
// stop handling focus request here as it is handled by external audio
// focus policy (return code will be handled in AudioManager)
return AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY;
} else {
// an error occured, client already dead, bail early
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
}
// handle the potential premature death of the new holder of the focus
// (premature death == death before abandoning focus)
// Register for client death notification
AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
try {
cb.linkToDeath(afdh, 0);
} catch (RemoteException e) {
// client has already died!
Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death");
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
// 如果申请的音频焦点已经在栈顶存在,则直接返回成功
if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
// if focus is already owned by this client and the reason for acquiring the focus
// hasn't changed, don't do anything
final FocusRequester fr = mFocusStack.peek();
if (fr.getGainRequest() == focusChangeHint && fr.getGrantFlags() == flags) {
// unlink death handler so it can be gc'ed.
// linkToDeath() creates a JNI global reference preventing collection.
cb.unlinkToDeath(afdh, 0);
notifyExtPolicyFocusGrant_syncAf(fr.toAudioFocusInfo(),
AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
// 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
// 如果焦点栈中有此焦点的clientid,又不是delay状态,则移除栈中的这个焦点信息,
// 这部分可以简单理解为用一个listener申请了两次不同的焦点,则会移除第一次申请的焦点信息
if (!focusGrantDelayed) {
mFocusStack.pop();
// the entry that was "popped" is the same that was "peeked" above
fr.release();
}
}
// focus requester might already be somewhere below in the stack, remove it
removeFocusStackEntry(clientId, false /* signal */, false /*notifyFocusFollowers*/);
final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb,
clientId, afdh, callingPackageName, Binder.getCallingUid(), this, sdk); //创建音频焦点请求者
if (focusGrantDelayed) {
// focusGrantDelayed being true implies we can't reassign focus right now
// which implies the focus stack is not empty.
//对于申请delay的焦点直接放入栈中被delay的焦点下面,比如当前栈中的焦点是电话,那么我们申请的这个允许delay的焦点就放到电话的下面
final int requestResult = pushBelowLockedFocusOwners(nfr);
if (requestResult != AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), requestResult);
}
return requestResult;
} else {
// propagate the focus change through the stack
//处理不是delay的焦点的情况 遍历焦点栈中所有焦点与之仲裁(主要是给处理栈中已有焦点对应的listener),并将此次申请的音频焦点放入栈中
if (!mFocusStack.empty()) {
propagateFocusLossFromGain_syncAf(focusChangeHint, nfr, forceDuck);
}
// push focus requester at the top of the audio focus stack
mFocusStack.push(nfr);
nfr.handleFocusGainFromRequest(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
}
notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(),
AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
if (ENFORCE_MUTING_FOR_RING_OR_CALL & enteringRingOrCall) {
runAudioCheckerForRingOrCallAsync(true/*enteringRingOrCall*/);
}
}//synchronized(mAudioFocusLock)
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
......
}
notifyExtFocusPolicyFocusRequest_syncAf
调用notifyExtFocusPolicyFocusRequest_syncAf方法,进行外部焦点请求处理:
//frameworks/base/service/java/com/android/server/audio/MediaFocusControl.java
public class MediaFocusControl implements PlayerFocusEnforcer {
@Nullable private IAudioPolicyCallback mFocusPolicy = null;
boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi,
IAudioFocusDispatcher fd, @NonNull IBinder cb) {
if (DEBUG) {
Log.v(TAG, "notifyExtFocusPolicyFocusRequest client="+afi.getClientId()
+ " dispatcher=" + fd);
}
synchronized (mExtFocusChangeLock) {
afi.setGen(mExtFocusChangeCounter++);
}
final FocusRequester existingFr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
boolean keepTrack = false;
if (existingFr != null) {
if (!existingFr.hasSameDispatcher(fd)) {
existingFr.release();
keepTrack = true;
}
} else {
keepTrack = true;
}
if (keepTrack) {
final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
try {
cb.linkToDeath(hdlr, 0);
} catch (RemoteException e) {
// client has already died!
return false;
}
// new focus (future) focus owner to keep track of
mFocusOwnersForFocusPolicy.put(afi.getClientId(),
new FocusRequester(afi, fd, cb, hdlr, this));
}
try {
//oneway
mFocusPolicy.notifyAudioFocusRequest(afi, AudioManager.AUDIOFOCUS_REQUEST_GRANTED); //调用IAudioPolicyCallback的notifyAudioFocusRequest方法
return true;
} catch (RemoteException e) {
Log.e(TAG, "Can't call notifyAudioFocusRequest() on IAudioPolicyCallback "
+ mFocusPolicy.asBinder(), e);
}
return false;
}
}
IAudioPolicyCallback的notifyAudioFocusRequest方法,IAudioPolicyCallback是一个接口,其实现在AudioPolicy中:
//frameworks/base/media/java/android/media/audiopolicy/AudioPolicy.java
public class AudioPolicy {
private final IAudioPolicyCallback mPolicyCb = new IAudioPolicyCallback.Stub() {
public void notifyAudioFocusGrant(AudioFocusInfo afi, int requestResult) {
sendMsg(MSG_FOCUS_GRANT, afi, requestResult);
if (DEBUG) {
Log.v(TAG, "notifyAudioFocusGrant: pack=" + afi.getPackageName() + " client="
+ afi.getClientId() + "reqRes=" + requestResult);
}
}
public void notifyAudioFocusLoss(AudioFocusInfo afi, boolean wasNotified) {
sendMsg(MSG_FOCUS_LOSS, afi, wasNotified ? 1 : 0);
if (DEBUG) {
Log.v(TAG, "notifyAudioFocusLoss: pack=" + afi.getPackageName() + " client="
+ afi.getClientId() + "wasNotified=" + wasNotified);
}
}
public void notifyAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
sendMsg(MSG_FOCUS_REQUEST, afi, requestResult); //发送MSG_FOCUS_REQUEST消息
if (DEBUG) {
Log.v(TAG, "notifyAudioFocusRequest: pack=" + afi.getPackageName() + " client="
+ afi.getClientId() + " gen=" + afi.getGen());
}
}
public void notifyAudioFocusAbandon(AudioFocusInfo afi) {
sendMsg(MSG_FOCUS_ABANDON, afi, 0 /* ignored */);
if (DEBUG) {
Log.v(TAG, "notifyAudioFocusAbandon: pack=" + afi.getPackageName() + " client="
+ afi.getClientId());
}
}
public void notifyMixStateUpdate(String regId, int state) {
for (AudioMix mix : mConfig.getMixes()) {
if (mix.getRegistration().equals(regId)) {
mix.mMixState = state;
sendMsg(MSG_MIX_STATE_UPDATE, mix, 0/*ignored*/);
if (DEBUG) {
Log.v(TAG, "notifyMixStateUpdate: regId=" + regId + " state=" + state);
}
}
}
}
public void notifyVolumeAdjust(int adjustment) {
sendMsg(MSG_VOL_ADJUST, null /* ignored */, adjustment);
if (DEBUG) {
Log.v(TAG, "notifyVolumeAdjust: " + adjustment);
}
}
public void notifyUnregistration() {
setRegistration(null);
}
}
}
发送MSG_FOCUS_REQUEST消息,在EventHandler中会处理这个消息:
//frameworks/base/media/java/android/media/audiopolicy/AudioPolicy.java
public class AudioPolicy {
private AudioPolicyFocusListener mFocusListener;
private class EventHandler extends Handler {
public EventHandler(AudioPolicy ap, Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_POLICY_STATUS_CHANGE:
onPolicyStatusChange();
break;
case MSG_FOCUS_GRANT:
if (mFocusListener != null) {
mFocusListener.onAudioFocusGrant(
(AudioFocusInfo) msg.obj, msg.arg1);
}
break;
case MSG_FOCUS_LOSS:
if (mFocusListener != null) {
mFocusListener.onAudioFocusLoss(
(AudioFocusInfo) msg.obj, msg.arg1 != 0);
}
break;
case MSG_MIX_STATE_UPDATE:
if (mStatusListener != null) {
mStatusListener.onMixStateUpdate((AudioMix) msg.obj);
}
break;
case MSG_FOCUS_REQUEST:
if (mFocusListener != null) {
mFocusListener.onAudioFocusRequest((AudioFocusInfo) msg.obj, msg.arg1);
} else { // should never be null, but don't crash
Log.e(TAG, "Invalid null focus listener for focus request event");
}
break;
case MSG_FOCUS_ABANDON:
if (mFocusListener != null) { // should never be null
mFocusListener.onAudioFocusAbandon((AudioFocusInfo) msg.obj);
} else { // should never be null, but don't crash
Log.e(TAG, "Invalid null focus listener for focus abandon event");
}
break;
case MSG_VOL_ADJUST:
if (mVolCb != null) {
mVolCb.onVolumeAdjustment(msg.arg1);
} else { // should never be null, but don't crash
Log.e(TAG, "Invalid null volume event");
}
break;
default:
Log.e(TAG, "Unknown event " + msg.what);
}
}
}
}
调用AudioPolicyFocusListener的onAudioFocusRequest方法,AudioPolicyFocusListener是一个接口,由CarZonesAudioFocus实现,因此会调用CarZonesAudioFocus的onAudioFocusRequest方法:
待更新