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

Commit f9283488 authored by Yan Han's avatar Yan Han Committed by Android (Google) Code Review
Browse files

Merge "AudioDeviceVolumeManager: Add APIs for listeners for device volume...

Merge "AudioDeviceVolumeManager: Add APIs for listeners for device volume behavior changes" into tm-dev
parents 325cbe55 19a45937
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
@@ -181,6 +181,80 @@ public class AudioDeviceVolumeManager {
        }
    }

    /**
     * Manages the OnDeviceVolumeBehaviorChangedListener listeners and
     * DeviceVolumeBehaviorDispatcherStub
     */
    private final CallbackUtil.LazyListenerManager<OnDeviceVolumeBehaviorChangedListener>
            mDeviceVolumeBehaviorChangedListenerMgr = new CallbackUtil.LazyListenerManager();

    /**
     * @hide
     * Interface definition of a callback to be invoked when the volume behavior of an audio device
     * is updated.
     */
    public interface OnDeviceVolumeBehaviorChangedListener {
        /**
         * Called on the listener to indicate that the volume behavior of a device has changed.
         * @param device the audio device whose volume behavior changed
         * @param volumeBehavior the new volume behavior of the audio device
         */
        void onDeviceVolumeBehaviorChanged(
                @NonNull AudioDeviceAttributes device,
                @AudioManager.DeviceVolumeBehavior int volumeBehavior);
    }

    /**
     * @hide
     * Adds a listener for being notified of changes to any device's volume behavior.
     * @throws SecurityException if the caller doesn't hold the required permission
     */
    @RequiresPermission(anyOf = {
            android.Manifest.permission.MODIFY_AUDIO_ROUTING,
            android.Manifest.permission.QUERY_AUDIO_STATE
    })
    public void addOnDeviceVolumeBehaviorChangedListener(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull OnDeviceVolumeBehaviorChangedListener listener)
            throws SecurityException {
        mDeviceVolumeBehaviorChangedListenerMgr.addListener(executor, listener,
                "addOnDeviceVolumeBehaviorChangedListener",
                () -> new DeviceVolumeBehaviorDispatcherStub());
    }

    /**
     * @hide
     * Removes a previously added listener of changes to device volume behavior.
     */

    @RequiresPermission(anyOf = {
            android.Manifest.permission.MODIFY_AUDIO_ROUTING,
            android.Manifest.permission.QUERY_AUDIO_STATE
    })
    public void removeOnDeviceVolumeBehaviorChangedListener(
            @NonNull OnDeviceVolumeBehaviorChangedListener listener) {
        mDeviceVolumeBehaviorChangedListenerMgr.removeListener(listener,
                "removeOnDeviceVolumeBehaviorChangedListener");
    }

    private final class DeviceVolumeBehaviorDispatcherStub
            extends IDeviceVolumeBehaviorDispatcher.Stub implements CallbackUtil.DispatcherStub {
        public void register(boolean register) {
            try {
                getService().registerDeviceVolumeBehaviorDispatcher(register, this);
            } catch (RemoteException e) {
                e.rethrowFromSystemServer();
            }
        }

        @Override
        public void dispatchDeviceVolumeBehaviorChanged(@NonNull AudioDeviceAttributes device,
                @AudioManager.DeviceVolumeBehavior int volumeBehavior) {
            mDeviceVolumeBehaviorChangedListenerMgr.callListeners((listener) ->
                    listener.onDeviceVolumeBehaviorChanged(device, volumeBehavior));
        }
    }

    private static IAudioService getService() {
        if (sService != null) {
            return sService;
+5 −1
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.media.IAudioRoutesObserver;
import android.media.IAudioServerStateDispatcher;
import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.ICommunicationDeviceDispatcher;
import android.media.IDeviceVolumeBehaviorDispatcher;
import android.media.IMuteAwaitConnectionCallback;
import android.media.IPlaybackConfigDispatcher;
import android.media.IRecordingConfigDispatcher;
@@ -44,7 +45,6 @@ import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
import android.media.ISpatializerOutputCallback;
import android.media.IVolumeController;
import android.media.IVolumeController;
import android.media.PlayerBase;
import android.media.VolumeInfo;
import android.media.VolumePolicy;
@@ -482,6 +482,10 @@ interface IAudioService {

    void setTestDeviceConnectionState(in AudioDeviceAttributes device, boolean connected);

    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING,android.Manifest.permission.QUERY_AUDIO_STATE})")
    void registerDeviceVolumeBehaviorDispatcher(boolean register,
            in IDeviceVolumeBehaviorDispatcher dispatcher);

    List<AudioFocusInfo> getFocusStack();

    boolean sendFocusLoss(in AudioFocusInfo focusLoser, in IAudioPolicyCallback apcb);
+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.AudioDeviceAttributes;

/**
 * AIDL for AudioService to signal changes to an audio device's volume behavior
 *
 * {@hide}
 */
oneway interface IDeviceVolumeBehaviorDispatcher {

    void dispatchDeviceVolumeBehaviorChanged(in AudioDeviceAttributes device,
            int deviceVolumeBehavior);

}
+98 −28
Original line number Diff line number Diff line
@@ -96,6 +96,7 @@ import android.media.IAudioServerStateDispatcher;
import android.media.IAudioService;
import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.ICommunicationDeviceDispatcher;
import android.media.IDeviceVolumeBehaviorDispatcher;
import android.media.IMuteAwaitConnectionCallback;
import android.media.IPlaybackConfigDispatcher;
import android.media.IRecordingConfigDispatcher;
@@ -341,6 +342,7 @@ public class AudioService extends IAudioService.Stub
    private static final int MSG_ADD_ASSISTANT_SERVICE_UID = 44;
    private static final int MSG_REMOVE_ASSISTANT_SERVICE_UID = 45;
    private static final int MSG_UPDATE_ACTIVE_ASSISTANT_SERVICE_UID = 46;
    private static final int MSG_DISPATCH_DEVICE_VOLUME_BEHAVIOR = 47;

    // start of messages handled under wakelock
    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
@@ -876,13 +878,23 @@ public class AudioService extends IAudioService.Stub

    /** @hide */
    public AudioService(Context context) {
        this(context, AudioSystemAdapter.getDefaultAdapter(),
        this(context,
                AudioSystemAdapter.getDefaultAdapter(),
                SystemServerAdapter.getDefaultAdapter(context),
                SettingsAdapter.getDefaultAdapter());
                SettingsAdapter.getDefaultAdapter(),
                null);
    }

    /**
     * @param context
     * @param audioSystem Adapter for {@link AudioSystem}
     * @param systemServer Adapter for privilieged functionality for system server components
     * @param settings Adapter for {@link Settings}
     * @param looper Looper to use for the service's message handler. If this is null, an
     *               {@link AudioSystemThread} is created as the messaging thread instead.
     */
    public AudioService(Context context, AudioSystemAdapter audioSystem,
            SystemServerAdapter systemServer, SettingsAdapter settings) {
            SystemServerAdapter systemServer, SettingsAdapter settings, @Nullable Looper looper) {
        sLifecycleLogger.log(new AudioEventLogger.StringEvent("AudioService()"));
        mContext = context;
        mContentResolver = context.getContentResolver();
@@ -1010,7 +1022,11 @@ public class AudioService extends IAudioService.Stub
                        MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM];
        }

        if (looper == null) {
            createAudioSystemThread();
        } else {
            mAudioHandler = new AudioHandler(looper);
        }

        AudioSystem.setErrorCallback(mAudioSystemCallback);

@@ -6457,34 +6473,41 @@ public class AudioService extends IAudioService.Stub
            return;
        }

        int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice(
                device.getType());
        setDeviceVolumeBehaviorInternal(audioSystemDeviceOut, deviceVolumeBehavior, pkgName);

        persistDeviceVolumeBehavior(audioSystemDeviceOut, deviceVolumeBehavior);
        setDeviceVolumeBehaviorInternal(device, deviceVolumeBehavior, pkgName);
        persistDeviceVolumeBehavior(device.getInternalType(), deviceVolumeBehavior);
    }

    private void setDeviceVolumeBehaviorInternal(int audioSystemDeviceOut,
    private void setDeviceVolumeBehaviorInternal(@NonNull AudioDeviceAttributes device,
            @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @NonNull String caller) {
        int audioSystemDeviceOut = device.getInternalType();
        boolean volumeBehaviorChanged = false;
        // update device masks based on volume behavior
        switch (deviceVolumeBehavior) {
            case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE:
                removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut);
                removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut);
                volumeBehaviorChanged |=
                        removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut)
                        | removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut);
                break;
            case AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED:
                removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut);
                addAudioSystemDeviceOutToFixedVolumeDevices(audioSystemDeviceOut);
                volumeBehaviorChanged |=
                        removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut)
                        | addAudioSystemDeviceOutToFixedVolumeDevices(audioSystemDeviceOut);
                break;
            case AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL:
                addAudioSystemDeviceOutToFullVolumeDevices(audioSystemDeviceOut);
                removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut);
                volumeBehaviorChanged |=
                        addAudioSystemDeviceOutToFullVolumeDevices(audioSystemDeviceOut)
                        | removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut);
                break;
            case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
            case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
                throw new IllegalArgumentException("Absolute volume unsupported for now");
        }

        if (volumeBehaviorChanged) {
            sendMsg(mAudioHandler, MSG_DISPATCH_DEVICE_VOLUME_BEHAVIOR, SENDMSG_QUEUE,
                    deviceVolumeBehavior, 0, device, /*delay*/ 0);
        }

        // log event and caller
        sDeviceLogger.log(new AudioEventLogger.StringEvent(
                "Volume behavior " + deviceVolumeBehavior + " for dev=0x"
@@ -7761,6 +7784,14 @@ public class AudioService extends IAudioService.Stub
    /** Handles internal volume messages in separate volume thread. */
    private class AudioHandler extends Handler {

        AudioHandler() {
            super();
        }

        AudioHandler(Looper looper) {
            super(looper);
        }

        private void setAllVolumes(VolumeStreamState streamState) {

            // Apply volume
@@ -8063,6 +8094,10 @@ public class AudioService extends IAudioService.Stub
                case MSG_UPDATE_ACTIVE_ASSISTANT_SERVICE_UID:
                    updateActiveAssistantServiceUids();
                    break;

                case MSG_DISPATCH_DEVICE_VOLUME_BEHAVIOR:
                    dispatchDeviceVolumeBehavior((AudioDeviceAttributes) msg.obj, msg.arg1);
                    break;
            }
        }
    }
@@ -9080,6 +9115,35 @@ public class AudioService extends IAudioService.Stub
        mMuteAwaitConnectionDispatchers.finishBroadcast();
    }

    final RemoteCallbackList<IDeviceVolumeBehaviorDispatcher> mDeviceVolumeBehaviorDispatchers =
            new RemoteCallbackList<IDeviceVolumeBehaviorDispatcher>();

    /**
     *  @see AudioDeviceVolumeManager#addOnDeviceVolumeBehaviorChangedListener and
     *  AudioDeviceVolumeManager#removeOnDeviceVolumeBehaviorChangedListener
     */
    public void registerDeviceVolumeBehaviorDispatcher(boolean register,
            @NonNull IDeviceVolumeBehaviorDispatcher dispatcher) {
        enforceQueryStateOrModifyRoutingPermission();
        Objects.requireNonNull(dispatcher);
        if (register) {
            mDeviceVolumeBehaviorDispatchers.register(dispatcher);
        } else {
            mDeviceVolumeBehaviorDispatchers.unregister(dispatcher);
        }
    }

    private void dispatchDeviceVolumeBehavior(AudioDeviceAttributes device, int volumeBehavior) {
        final int dispatchers = mDeviceVolumeBehaviorDispatchers.beginBroadcast();
        for (int i = 0; i < dispatchers; i++) {
            try {
                mDeviceVolumeBehaviorDispatchers.getBroadcastItem(i)
                        .dispatchDeviceVolumeBehaviorChanged(device, volumeBehavior);
            } catch (RemoteException e) {
            }
        }
        mDeviceVolumeBehaviorDispatchers.finishBroadcast();
    }

    //==========================================================================================
    // Device orientation
@@ -9310,14 +9374,20 @@ public class AudioService extends IAudioService.Stub
                if (DEBUG_VOL) {
                    Log.d(TAG, "CEC sink: setting HDMI as full vol device");
                }
                addAudioSystemDeviceOutToFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI);
                setDeviceVolumeBehaviorInternal(
                        new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
                        AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL,
                        "AudioService.updateHdmiCecSinkLocked()");
            } else {
                if (DEBUG_VOL) {
                    Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device");
                }
                // Android TV devices without CEC service apply software volume on
                // HDMI output
                removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI);
                setDeviceVolumeBehaviorInternal(
                        new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
                        AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE,
                        "AudioService.updateHdmiCecSinkLocked()");
            }
            postUpdateVolumeStatesForAudioDevice(AudioSystem.DEVICE_OUT_HDMI,
                    "HdmiPlaybackClient.DisplayStatusCallback");
@@ -11463,8 +11533,8 @@ public class AudioService extends IAudioService.Stub
                continue;
            }

            setDeviceVolumeBehaviorInternal(deviceType, deviceVolumeBehavior,
                    "AudioService.restoreDeviceVolumeBehavior()");
            setDeviceVolumeBehaviorInternal(new AudioDeviceAttributes(deviceType, ""),
                    deviceVolumeBehavior, "AudioService.restoreDeviceVolumeBehavior()");
        }
    }

@@ -11479,36 +11549,36 @@ public class AudioService extends IAudioService.Stub
                != AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET;
    }

    private void addAudioSystemDeviceOutToFixedVolumeDevices(int audioSystemDeviceOut) {
    private boolean addAudioSystemDeviceOutToFixedVolumeDevices(int audioSystemDeviceOut) {
        if (DEBUG_VOL) {
            Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
                    + " to mFixedVolumeDevices");
        }
        mFixedVolumeDevices.add(audioSystemDeviceOut);
        return mFixedVolumeDevices.add(audioSystemDeviceOut);
    }

    private void removeAudioSystemDeviceOutFromFixedVolumeDevices(int audioSystemDeviceOut) {
    private boolean removeAudioSystemDeviceOutFromFixedVolumeDevices(int audioSystemDeviceOut) {
        if (DEBUG_VOL) {
            Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
                    + " from mFixedVolumeDevices");
        }
        mFixedVolumeDevices.remove(audioSystemDeviceOut);
        return mFixedVolumeDevices.remove(audioSystemDeviceOut);
    }

    private void addAudioSystemDeviceOutToFullVolumeDevices(int audioSystemDeviceOut) {
    private boolean addAudioSystemDeviceOutToFullVolumeDevices(int audioSystemDeviceOut) {
        if (DEBUG_VOL) {
            Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
                    + " to mFullVolumeDevices");
        }
        mFullVolumeDevices.add(audioSystemDeviceOut);
        return mFullVolumeDevices.add(audioSystemDeviceOut);
    }

    private void removeAudioSystemDeviceOutFromFullVolumeDevices(int audioSystemDeviceOut) {
    private boolean removeAudioSystemDeviceOutFromFullVolumeDevices(int audioSystemDeviceOut) {
        if (DEBUG_VOL) {
            Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
                    + " from mFullVolumeDevices");
        }
        mFullVolumeDevices.remove(audioSystemDeviceOut);
        return mFullVolumeDevices.remove(audioSystemDeviceOut);
    }

    //====================
+1 −1
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ public class AudioServiceTest {
        mSpySystemServer = spy(new NoOpSystemServerAdapter());
        mSettingsAdapter = new NoOpSettingsAdapter();
        mAudioService = new AudioService(mContext, mAudioSystem, mSpySystemServer,
                mSettingsAdapter);
                mSettingsAdapter, null);
    }

    /**
Loading