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

Commit ebadb69b authored by Paul Wang's avatar Paul Wang
Browse files

Add listener API to subscribe for routing change per AudioAttributes

Bug: 259094683
Test: atest AudioHostTest CtsMediaAudioTestCases:DevicesForAttributesTest
Change-Id: I4ac24b73e60014c15c7c2eb14622b14f9f597ac4
parent 383a0536
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -6604,6 +6604,7 @@ package android.media {
  public class AudioManager {
    method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addAssistantServicesUids(@NonNull int[]);
    method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public void addOnDevicesForAttributesChangedListener(@NonNull android.media.AudioAttributes, @NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnDevicesForAttributesChangedListener);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnNonDefaultDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnNonDefaultDevicesForStrategyChangedListener) throws java.lang.SecurityException;
    method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException;
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForCapturePresetChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener) throws java.lang.SecurityException;
@@ -6644,6 +6645,7 @@ package android.media {
    method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeAssistantServicesUids(@NonNull int[]);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removeDeviceAsNonDefaultForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
    method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public void removeOnDevicesForAttributesChangedListener(@NonNull android.media.AudioManager.OnDevicesForAttributesChangedListener);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnNonDefaultDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnNonDefaultDevicesForStrategyChangedListener);
    method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForCapturePresetChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener);
@@ -6701,6 +6703,10 @@ package android.media {
    field public static final int EVENT_TIMEOUT = 2; // 0x2
  }
  public static interface AudioManager.OnDevicesForAttributesChangedListener {
    method public void onDevicesForAttributesChanged(@NonNull android.media.AudioAttributes, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
  }
  public static interface AudioManager.OnNonDefaultDevicesForStrategyChangedListener {
    method public void onNonDefaultDevicesForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
  }
+111 −0
Original line number Diff line number Diff line
@@ -5855,6 +5855,117 @@ public class AudioManager {
        }
    }

    // Each listener corresponds to a unique callback stub because each listener can subscribe to
    // different AudioAttributes.
    private final ConcurrentHashMap<OnDevicesForAttributesChangedListener,
            IDevicesForAttributesCallbackStub> mDevicesForAttributesListenerToStub =
                    new ConcurrentHashMap<>();

    private static final class IDevicesForAttributesCallbackStub
            extends IDevicesForAttributesCallback.Stub {
        ListenerInfo<OnDevicesForAttributesChangedListener> mInfo;

        IDevicesForAttributesCallbackStub(@NonNull OnDevicesForAttributesChangedListener listener,
                @NonNull Executor executor) {
            mInfo = new ListenerInfo<>(listener, executor);
        }

        public void register(boolean register, AudioAttributes attributes) {
            try {
                if (register) {
                    getService().addOnDevicesForAttributesChangedListener(attributes, this);
                } else {
                    getService().removeOnDevicesForAttributesChangedListener(this);
                }
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

        @Override
        public void onDevicesForAttributesChanged(AudioAttributes attributes, boolean forVolume,
                List<AudioDeviceAttributes> devices) {
            // forVolume is ignored. The case where it is `true` is not handled.
            mInfo.mExecutor.execute(() ->
                    mInfo.mListener.onDevicesForAttributesChanged(
                            attributes, devices));
        }
    }

    /**
     * @hide
     * Interface to be notified of when routing changes for the registered audio attributes.
     */
    @SystemApi
    public interface OnDevicesForAttributesChangedListener {
        /**
         * Called on the listener to indicate that the audio devices for the given audio
         * attributes have changed.
         * @param attributes the {@link AudioAttributes} whose routing changed
         * @param devices a list of newly routed audio devices
         */
        void onDevicesForAttributesChanged(@NonNull AudioAttributes attributes,
                @NonNull List<AudioDeviceAttributes> devices);
    }

    /**
     * @hide
     * Adds a listener for being notified of routing changes for the given {@link AudioAttributes}.
     * @param attributes the {@link AudioAttributes} to listen for routing changes
     * @param executor
     * @param listener
     */
    @SystemApi
    @RequiresPermission(anyOf = {
            android.Manifest.permission.MODIFY_AUDIO_ROUTING,
            android.Manifest.permission.QUERY_AUDIO_STATE
    })
    public void addOnDevicesForAttributesChangedListener(@NonNull AudioAttributes attributes,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull OnDevicesForAttributesChangedListener listener) {
        Objects.requireNonNull(attributes);
        Objects.requireNonNull(executor);
        Objects.requireNonNull(listener);

        synchronized (mDevicesForAttributesListenerToStub) {
            IDevicesForAttributesCallbackStub callbackStub =
                    mDevicesForAttributesListenerToStub.get(listener);

            if (callbackStub == null) {
                callbackStub = new IDevicesForAttributesCallbackStub(listener, executor);
                mDevicesForAttributesListenerToStub.put(listener, callbackStub);
            }

            callbackStub.register(true, attributes);
        }
    }

    /**
     * @hide
     * Removes a previously registered listener for being notified of routing changes for the given
     * {@link AudioAttributes}.
     * @param listener
     */
    @SystemApi
    @RequiresPermission(anyOf = {
            android.Manifest.permission.MODIFY_AUDIO_ROUTING,
            android.Manifest.permission.QUERY_AUDIO_STATE
    })
    public void removeOnDevicesForAttributesChangedListener(
            @NonNull OnDevicesForAttributesChangedListener listener) {
        Objects.requireNonNull(listener);

        synchronized (mDevicesForAttributesListenerToStub) {
            IDevicesForAttributesCallbackStub callbackStub =
                    mDevicesForAttributesListenerToStub.get(listener);
            if (callbackStub != null) {
                callbackStub.register(false, null /* attributes */);
            }

            mDevicesForAttributesListenerToStub.remove(listener);
        }
    }

    /**
     * Get the audio devices that would be used for the routing of the given audio attributes.
     * These are the devices anticipated to play sound from an {@link AudioTrack} created with
+7 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.media.IAudioServerStateDispatcher;
import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.ICommunicationDeviceDispatcher;
import android.media.IDeviceVolumeBehaviorDispatcher;
import android.media.IDevicesForAttributesCallback;
import android.media.IMuteAwaitConnectionCallback;
import android.media.IPlaybackConfigDispatcher;
import android.media.IPreferredMixerAttributesDispatcher;
@@ -356,6 +357,12 @@ interface IAudioService {

    List<AudioDeviceAttributes> getDevicesForAttributesUnprotected(in AudioAttributes attributes);

    void addOnDevicesForAttributesChangedListener(in AudioAttributes attributes,
            in IDevicesForAttributesCallback callback);

    oneway void removeOnDevicesForAttributesChangedListener(
            in IDevicesForAttributesCallback callback);

    int setAllowedCapturePolicy(in int capturePolicy);

    int getAllowedCapturePolicy();
+33 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

import android.media.AudioAttributes;
import android.media.AudioDeviceAttributes;

/**
 * AIDL for AudioService to signal updates of audio devices routing for attributes.
 *
 * {@hide}
 */
oneway interface IDevicesForAttributesCallback {

    void onDevicesForAttributesChanged(in AudioAttributes attributes, boolean forVolume,
            in List<AudioDeviceAttributes> devices);

}
+20 −0
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ import android.media.IAudioService;
import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.ICommunicationDeviceDispatcher;
import android.media.IDeviceVolumeBehaviorDispatcher;
import android.media.IDevicesForAttributesCallback;
import android.media.IMuteAwaitConnectionCallback;
import android.media.IPlaybackConfigDispatcher;
import android.media.IPreferredMixerAttributesDispatcher;
@@ -3124,6 +3125,25 @@ public class AudioService extends IAudioService.Stub
        return mAudioSystem.getDevicesForAttributes(attributes, forVolume);
    }
    /**
     * @see AudioManager#addOnDevicesForAttributesChangedListener(
     *      AudioAttributes, Executor, OnDevicesForAttributesChangedListener)
     */
    public void addOnDevicesForAttributesChangedListener(AudioAttributes attributes,
            IDevicesForAttributesCallback callback) {
        mAudioSystem.addOnDevicesForAttributesChangedListener(
                attributes, false /* forVolume */, callback);
    }
    /**
     * @see AudioManager#removeOnDevicesForAttributesChangedListener(
     *      OnDevicesForAttributesChangedListener)
     */
    public void removeOnDevicesForAttributesChangedListener(
            IDevicesForAttributesCallback callback) {
        mAudioSystem.removeOnDevicesForAttributesChangedListener(callback);
    }
    // pre-condition: event.getKeyCode() is one of KeyEvent.KEYCODE_VOLUME_UP,
    //                                   KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_MUTE
    public void handleVolumeKey(@NonNull KeyEvent event, boolean isOnTv,
Loading