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

Commit b337200e authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "AudioPolicy: focus stack query, send focus loss APIs"

parents 24129554 823994ab
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -5875,9 +5875,11 @@ package android.media.audiopolicy {
    method public android.media.AudioTrack createAudioTrackSource(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
    method public android.media.AudioTrack createAudioTrackSource(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
    method public int detachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>);
    method public int detachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>);
    method public int getFocusDuckingBehavior();
    method public int getFocusDuckingBehavior();
    method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioFocusInfo> getFocusStack();
    method public int getStatus();
    method public int getStatus();
    method public boolean removeUidDeviceAffinity(int);
    method public boolean removeUidDeviceAffinity(int);
    method public boolean removeUserIdDeviceAffinity(int);
    method public boolean removeUserIdDeviceAffinity(int);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean sendFocusLoss(@NonNull android.media.AudioFocusInfo) throws java.lang.IllegalStateException;
    method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
    method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
    method public void setRegistration(String);
    method public void setRegistration(String);
    method public boolean setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
    method public boolean setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
+4 −0
Original line number Original line Diff line number Diff line
@@ -460,4 +460,8 @@ interface IAudioService {
            boolean register);
            boolean register);


    void setTestDeviceConnectionState(in AudioDeviceAttributes device, boolean connected);
    void setTestDeviceConnectionState(in AudioDeviceAttributes device, boolean connected);

    List<AudioFocusInfo> getFocusStack();

    boolean sendFocusLoss(in AudioFocusInfo focusLoser, in IAudioPolicyCallback apcb);
}
}
+41 −1
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package android.media.audiopolicy;
import android.annotation.IntDef;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.annotation.UserIdInt;
@@ -230,7 +231,7 @@ public class AudioPolicy {
         * If set to {@code true}, it is mandatory to set an
         * If set to {@code true}, it is mandatory to set an
         * {@link AudioPolicy.AudioPolicyFocusListener} in order to successfully build
         * {@link AudioPolicy.AudioPolicyFocusListener} in order to successfully build
         * an {@code AudioPolicy} instance.
         * an {@code AudioPolicy} instance.
         * @param enforce true if the policy will govern audio focus decisions.
         * @param isFocusPolicy true if the policy will govern audio focus decisions.
         * @return the same Builder instance.
         * @return the same Builder instance.
         */
         */
        @NonNull
        @NonNull
@@ -722,6 +723,45 @@ public class AudioPolicy {
        }
        }
    }
    }


    /**
     * Returns the list of entries in the focus stack.
     * The list is ordered with increasing rank of focus ownership, where the last entry is at the
     * top of the focus stack and is the current focus owner.
     * @return the ordered list of focus owners
     * @see AudioManager#registerAudioPolicy(AudioPolicy)
     */
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    public @NonNull List<AudioFocusInfo> getFocusStack() {
        try {
            return getService().getFocusStack();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Send AUDIOFOCUS_LOSS to a specific stack entry, causing it to be notified of the focus
     * loss, and for it to exit the focus stack (its focus listener will not be invoked after that).
     * This operation is only valid for a registered policy (with
     * {@link AudioManager#registerAudioPolicy(AudioPolicy)}) that is also set as the policy focus
     * listener (with {@link Builder#setAudioPolicyFocusListener(AudioPolicyFocusListener)}.
     * @param focusLoser the stack entry that is exiting the stack through a focus loss
     * @return false if the focusLoser wasn't found in the stack, true otherwise
     * @throws IllegalStateException if used on an unregistered policy, or a registered policy
     *     with no {@link AudioPolicyFocusListener} set
     * @see AudioManager#registerAudioPolicy(AudioPolicy)
     * @see Builder#setAudioPolicyStatusListener(AudioPolicyStatusListener)
     */
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    public boolean sendFocusLoss(@NonNull AudioFocusInfo focusLoser) throws IllegalStateException {
        Objects.requireNonNull(focusLoser);
        try {
            return getService().sendFocusLoss(focusLoser, cb());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
    /**
     * Create an {@link AudioRecord} instance that is associated with the given {@link AudioMix}.
     * Create an {@link AudioRecord} instance that is associated with the given {@link AudioMix}.
     * Audio buffers recorded through the created instance will contain the mix of the audio
     * Audio buffers recorded through the created instance will contain the mix of the audio
+21 −0
Original line number Original line Diff line number Diff line
@@ -10142,6 +10142,27 @@ public class AudioService extends IAudioService.Stub
        return AudioManager.SUCCESS;
        return AudioManager.SUCCESS;
    }
    }


    /** @see AudioPolicy#getFocusStack() */
    public List<AudioFocusInfo> getFocusStack() {
        enforceModifyAudioRoutingPermission();
        return mMediaFocusControl.getFocusStack();
    }

    /** @see AudioPolicy#sendFocusLoss */
    public boolean sendFocusLoss(@NonNull AudioFocusInfo focusLoser,
            @NonNull IAudioPolicyCallback apcb) {
        Objects.requireNonNull(focusLoser);
        Objects.requireNonNull(apcb);
        enforceModifyAudioRoutingPermission();
        if (!mAudioPolicies.containsKey(apcb.asBinder())) {
            throw new IllegalStateException("Only registered AudioPolicy can change focus");
        }
        if (!mAudioPolicies.get(apcb.asBinder()).mHasFocusListener) {
            throw new IllegalStateException("AudioPolicy must have focus listener to change focus");
        }
        return mMediaFocusControl.sendFocusLoss(focusLoser);
    }

    /** see AudioManager.hasRegisteredDynamicPolicy */
    /** see AudioManager.hasRegisteredDynamicPolicy */
    public boolean hasRegisteredDynamicPolicy() {
    public boolean hasRegisteredDynamicPolicy() {
        synchronized (mAudioPolicies) {
        synchronized (mAudioPolicies) {
+46 −0
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@ import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.AudioSystem;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioFocusDispatcher;
import android.media.MediaMetrics;
import android.media.MediaMetrics;
import android.media.audiopolicy.AudioPolicy;
import android.media.audiopolicy.IAudioPolicyCallback;
import android.media.audiopolicy.IAudioPolicyCallback;
import android.os.Binder;
import android.os.Binder;
import android.os.Build;
import android.os.Build;
@@ -221,6 +222,51 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
        }
        }
    }
    }


    /**
     * Return a copy of the focus stack for external consumption (composed of AudioFocusInfo
     * instead of FocusRequester instances)
     * @return a SystemApi-friendly version of the focus stack, in the same order (last entry
     *         is top of focus stack, i.e. latest focus owner)
     * @see AudioPolicy#getFocusStack()
     */
    @NonNull List<AudioFocusInfo> getFocusStack() {
        synchronized (mAudioFocusLock) {
            final ArrayList<AudioFocusInfo> stack = new ArrayList<>(mFocusStack.size());
            for (FocusRequester fr : mFocusStack) {
                stack.add(fr.toAudioFocusInfo());
            }
            return stack;
        }
    }

    /**
     * Send AUDIOFOCUS_LOSS to a specific stack entry.
     * Note this method is supporting an external API, and is restricted to LOSS in order to
     * prevent allowing the stack to be in an invalid state (e.g. entry inside stack has focus)
     * @param focusLoser the stack entry that is exiting the stack through a focus loss
     * @return false if the focusLoser wasn't found in the stack, true otherwise
     * @see AudioPolicy#sendFocusLoss(AudioFocusInfo)
     */
    boolean sendFocusLoss(@NonNull AudioFocusInfo focusLoser) {
        synchronized (mAudioFocusLock) {
            FocusRequester loserToRemove = null;
            for (FocusRequester fr : mFocusStack) {
                if (fr.getClientId().equals(focusLoser.getClientId())) {
                    fr.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS, null,
                            false /*forceDuck*/);
                    loserToRemove = fr;
                    break;
                }
            }
            if (loserToRemove != null) {
                mFocusStack.remove(loserToRemove);
                loserToRemove.release();
                return true;
            }
        }
        return false;
    }

    @GuardedBy("mAudioFocusLock")
    @GuardedBy("mAudioFocusLock")
    private void notifyTopOfAudioFocusStack() {
    private void notifyTopOfAudioFocusStack() {
        // notify the top of the stack it gained focus
        // notify the top of the stack it gained focus