Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c148c4e authored by Phil Yan's avatar Phil Yan
Browse files

Create hasAudioFocus to support multi-focus

Centralize the logic for checking audio focus state within
MediaFocusControl. Previously, consumers like AppStateHelper
implemented their own checks by directly inspecting the focus stack.
This approach was brittle and did not account for the multi-audio
focus list, leading to incorrect results when the feature was enabled.

This change introduces `hasAudioFocus` and updates `hasAudioFocusUsers`
in MediaFocusControl, making it the single source of truth for focus
state queries. These methods check both the main focus stack and the
multi-focus list.

By centralizing the logic, callers are now agnostic to the internal
implementation of focus management, making the system more robust and
easier to maintain.

Bug: 416963897
Flag: android.media.audio.audio_focus_desktop
Test: atest AudioFocusTest
Change-Id: I1e557df5ae59cecd813210334a6a2e5d6d9a2d77
parent b655c60a
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -746,6 +746,9 @@ interface IAudioService {
    @EnforcePermission("MODIFY_AUDIO_ROUTING")
    List<AudioFocusInfo> getFocusStack();

    @EnforcePermission("QUERY_AUDIO_STATE")
    boolean hasAudioFocus(String packageName);

    @EnforcePermission("MODIFY_AUDIO_ROUTING")
    oneway void sendFocusLossAndUpdate(in AudioFocusInfo focusLoser, in IAudioPolicyCallback apcb);

+15 −0
Original line number Diff line number Diff line
@@ -14579,6 +14579,21 @@ public class AudioService extends IAudioService.Stub
        return mMediaFocusControl.getFocusStack();
    }
    /**
     * Checks if a given package currently holds any type of audio focus.
     * <p>This method considers all forms of audio focus, including traditional exclusive/transient
     * focus from the main focus stack and concurrent focus when multi-audio focus is enabled.
     *
     * @param packageName The package name to check for audio focus.
     * @return {@code true} if the package holds any audio focus, {@code false} otherwise.
     */
    @android.annotation.EnforcePermission(QUERY_AUDIO_STATE)
    public boolean hasAudioFocus(String packageName) {
        super.hasAudioFocus_enforcePermission();
        return mMediaFocusControl.hasAudioFocus(packageName);
    }
    /**
     * @param focusLoser non-null entry that may be in the stack
     * @see AudioPolicy#sendFocusLossAndUpdate(AudioFocusInfo)
+23 −1
Original line number Diff line number Diff line
@@ -251,9 +251,31 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
        }
    }

    /*package*/ boolean hasAudioFocus(String packageName) {
        synchronized (mAudioFocusLock) {
            Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
            while (stackIterator.hasNext()) {
                if (stackIterator.next().hasSamePackage(packageName)) {
                    return true;
                }
            }

            if (mMultiAudioFocusEnabled) {
                Iterator<FocusRequester> listIterator = mMultiAudioFocusList.iterator();
                while (listIterator.hasNext()) {
                    if (listIterator.next().hasSamePackage(packageName)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /*package*/ boolean hasAudioFocusUsers() {
        synchronized (mAudioFocusLock) {
            return !mFocusStack.empty();
            return !mFocusStack.empty() || (mMultiAudioFocusEnabled
                    && !mMultiAudioFocusList.isEmpty());
        }
    }

+1 −4
Original line number Diff line number Diff line
@@ -77,10 +77,7 @@ public class AppStateHelper {
        var audioService = IAudioService.Stub.asInterface(
                ServiceManager.getService(Context.AUDIO_SERVICE));
        try {
            var focusInfos = audioService.getFocusStack();
            int size = focusInfos.size();
            var audioFocusPackage = (size > 0) ? focusInfos.get(size - 1).getPackageName() : null;
            return TextUtils.equals(packageName, audioFocusPackage);
            return audioService.hasAudioFocus(packageName);
        } catch (Exception ignore) {
        }
        return false;