旧焦点处理
示例调用链:
- requestAudioFocus() → propagateFocusLossFromGain_syncAf() → handleFocusLossFromGain()。
- 系统事件(如来电)→ 强制焦点变化 → handleFocusLossFromGain()。
函数
propagateFocusLossFromGain_syncAf 焦点持有者发生的焦点丢失通知
主要功能:
• 当新的音频焦点请求到来时,通知当前所有焦点持有者可能发生的焦点丢失• 根据新的焦点增益类型决定哪些现有焦点持有者需要永久放弃焦点
• 清理那些需要永久放弃焦点的持有者
关键处理逻辑:
• 遍历当前焦点栈中的所有持有者,通知它们新的焦点变化• 对于多音频焦点模式,同样处理额外的焦点持有者列表
• 收集所有需要永久放弃焦点的持有者并移除它们
参数作用:
• focusGain: 新请求的焦点增益类型(如AUDIOFOCUS_GAIN等)• fr: 新的焦点请求者对象
• forceDuck: 是否强制应用ducking效果(降低音量而非完全停止)
多音频焦点支持:
• 当启用多音频焦点(mMultiAudioFocusEnabled)时,会额外处理mMultiAudioFocusList中的焦点持有者
/*** 当新的焦点请求到来时,传播相关的焦点丢失通知到当前焦点栈中的各个持有者。* 同时会移除那些收到永久性焦点丢失的栈条目。* * @param focusGain 新的焦点增益类型,将被添加到栈顶* @param fr 新的焦点请求者* @param forceDuck 是否强制应用 ducking 效果*/
@GuardedBy("mAudioFocusLock")
private void propagateFocusLossFromGain_syncAf(int focusGain, final FocusRequester fr,boolean forceDuck) {if (DEBUG) {Log.i(TAG, "propagateFocusLossFromGain_syncAf gain:" + focusGain);}// 创建一个列表来存储需要移除的客户端IDfinal List<String> clientsToRemove = new LinkedList<String>();// 遍历音频焦点栈,通知所有条目关于新的外部焦点增益if (!mFocusStack.empty()) {for (FocusRequester focusLoser : mFocusStack) {if (DEBUG) {Log.i(TAG, "propagateFocusLossFromGain_syncAf checking client:"+ focusLoser.getClientId());}// 处理焦点丢失,并判断是否是永久性丢失final boolean isDefinitiveLoss =focusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck);if (isDefinitiveLoss) {// 如果是永久性丢失,则添加到移除列表clientsToRemove.add(focusLoser.getClientId());}}} else if (DEBUG) {Log.i(TAG, "propagateFocusLossFromGain_syncAf empty stack");}// 如果启用了多音频焦点且列表不为空,同样处理这些焦点持有者if (mMultiAudioFocusEnabled && !mMultiAudioFocusList.isEmpty()) {for (FocusRequester multifocusLoser : mMultiAudioFocusList) {final boolean isDefinitiveLoss =multifocusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck);if (isDefinitiveLoss) {clientsToRemove.add(multifocusLoser.getClientId());}}}// 移除所有需要移除的焦点持有者for (String clientToRemove : clientsToRemove) {removeFocusStackEntry(clientToRemove, false /*signal*/,true /*notifyFocusFollowers*/);}
}
handleFocusLossFromGain
主要执行场景:
-
当有新的音频焦点请求时
• 当一个新的应用请求音频焦点(如通过 requestAudioFocus())时,系统需要通知当前持有焦点的应用可能会失去焦点。• 该方法会被调用来检查当前焦点持有者是否需要因为新的焦点请求而失去焦点(或调整行为,如 ducking)。
-
焦点栈变化时
• 在 propagateFocusLossFromGain_syncAf() 方法中,会遍历当前的焦点栈,对每个焦点持有者调用 handleFocusLossFromGain,以决定它们是否需要失去焦点或调整行为。 -
强制焦点变化时
• 在某些系统事件(如来电、通知、系统强制打断)时,会触发焦点重新分配,该方法会被调用来处理当前焦点持有者的状态。
方法的作用:
• 该方法会根据新的焦点请求类型(如 AUDIOFOCUS_GAIN、AUDIOFOCUS_GAIN_TRANSIENT 等)和当前焦点持有者的状态,决定是否需要:
• 完全失去焦点(AUDIOFOCUS_LOSS)。
• 临时失去焦点(如 AUDIOFOCUS_LOSS_TRANSIENT)。
• 降低音量(ducking,AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK)。
• 返回 true 表示焦点持有者需要被移除出焦点栈(永久失去焦点),false 表示可以保留在栈中(如临时失去焦点后可能恢复)。
/*** 处理由于给定焦点增益导致的焦点丢失。* @param focusGain 导致焦点丢失的焦点增益类型* @param frWinner 新的焦点所有者* @param forceDuck 是否强制闪避* @return 如果焦点丢失是永久性的则返回true,否则返回false*/
@GuardedBy