赞
踩
摘要:Android 9 的音频焦点仲裁策略基本上可以用一句话来概括:后来居上,电话最大。这种策略显然是不能满足音频焦点仲裁的复杂需求的,所以Google在Android 10 中做了大幅度的改进,其中最主要的就是引入了音频焦点判断矩阵,通过矩阵来仲裁后来者是否可以抢占当前焦点。
由于Android9的音频焦点策略基本不能满足项目需求,所以一般会引入外部焦点仲裁策略,不知道如何引入的可以参考这篇文章:自定义音频焦点策略的实现。既然要引入,何不引入Android 10 的音频焦点策略呢?
变量 | 类型 | 说明 |
---|---|---|
AudioFocusInfo | 类 | 描述焦点申请者属性 |
FocusEntry | 内部类 | 对AudioFocusInfo和Context的封装 |
sInteractionMatrix | 二维数组 | 仲裁焦点申请结果 |
mFocusHolders | 全局变量,HashMap | 保存当前焦点持有者 |
mFocusLosers | 全局变量,HashMap | 保存暂时失去焦点并等待重新获得焦点的申请 |
losers | 局部变量,ArrayList | 保存失去焦点但失去焦点类型尚未确定的申请 |
blocked | 局部变量,ArrayList | 保存mFocusLosers中可以被当前申请者抢占的申请 |
permanentlyLost | 局部变量,ArrayList | 保存永久失去焦点的申请 |
申请焦点的入口函数是:evaluateFocusRequest
,接受一个AudioFocusInfo
类型参数
新建两个boolean类型参数用来描述焦点申请者属性:
permanent
:描述申请者是否申请永久获取焦点(即申请类型是否为AUDIOFOCUS_GAIN)
allowDucking
:描述申请者是否申请暂时获取焦点且允许混音(即申请类型是否为AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
// Is this a request for premanant focus?
// AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE -- Means Notifications should be denied
// AUDIOFOCUS_GAIN_TRANSIENT -- Means current focus holders should get transient loss
// AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK -- Means other can duck (no loss message from us)
// NOTE: We expect that in practice it will be permanent for all media requests and
// transient for everything else, but that isn't currently an enforced requirement.
final boolean permanent =
(afi.getGainRequest() == AudioManager.AUDIOFOCUS_GAIN);
//final boolean allowDucking =
// (afi.getGainRequest() == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
// only interaction matrix can decide if ducking allowed
final boolean allowDucking =
(afi.getGainRequest() == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
将usage转化为Context:(什么是usage和Context?参考此处)
// Convert from audio attributes "usage" to HAL level "context"
final int requestedContext = mCarAudioService.getContextForUsage(
afi.getAttributes().getUsage());
防止已经拥有或者暂时失去焦点的引用再次申请焦点,新建两个FocusEntry
:
replacedCurrentEntry
:当已经拥有焦点的应用再次申请焦点时,对这个变量赋值,如果申请成功则删除replacedCurrentEntry
,用新的请申请代替
replacedBlockedEntry
:当暂时失去焦点的应用再次申请焦点时,对这个变量赋值,如果申请成功则删除replacedBlockedEntry
,用新的请申请代替
// If we happen to find entries that this new request should replace, we'll store them here.
// This happens when a client makes a second AF request on the same listener.
// After we've granted audio focus to our current request, we'll abandon these requests.
FocusEntry replacedCurrentEntry = null;
FocusEntry replacedBlockedEntry = null;
接下来会遍历mFocusHolders
:
首先判断如果当前申请者的requestedContext
是NOTIFICATION
并且mFocusHolders
已经存在一个暂时独占焦点的申请者(AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE),则直接返回申请失败
// If this request is for Notifications and a current focus holder has specified
// AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE, then reject the request.
// This matches the hardwired behavior in the default audio policy engine which apps
// might expect (The interaction matrix doesn't have any provision for dealing with
// override flags like this).
if ((requestedContext == ContextNumber.NOTIFICATION) &&
(entry.mAfi.getGainRequest() ==
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
接着判断是否是同一个应用申请的焦点,如果是同一个应用且申请的是同一个Context类型的焦点,则将目前mFocusHolders
中的此应用的entry赋值给replacedCurrentEntry,之后如果焦点申请成功则会将这个entry删除并将新的加入,如果申请的是不同的Context类型,则直接返回申请失败
// We don't allow sharing listeners (client IDs) between two concurrent requests // (because the app would have no way to know to which request a later event applied) if (afi.getClientId().equals(entry.mAfi.getClientId())) { if (entry.mAudioContext == requestedContext) { // This is a request from a current focus holder. // Abandon the previous request (without sending a LOSS notification to it), // and don't check the interaction matrix for it. Slog.i(TAG, "Replacing accepted request from same client"); replacedCurrentEntry = entry; continue; } else { // Trivially reject a request for a different USAGE Slog.e(TAG, "Client " + entry.getClientId() + " has already requested focus " + "for " + entry.mAfi.getAttributes().usageToString() + " - cannot " + "request focus for " + afi.<
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。