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

Commit 0c139822 authored by Madhava Srinivasan's avatar Madhava Srinivasan Committed by Automerger Merge Worker
Browse files

Merge "Persisting setDeviceVolumeBehavior calls" into rvc-dev am: d03a5993

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11838112

Change-Id: I6aadfa549c3245097c117795896c486c4f516d71
parents add52bde d03a5993
Loading
Loading
Loading
Loading
+21 −3
Original line number Diff line number Diff line
@@ -4597,6 +4597,12 @@ public class AudioManager {
        }
    }

    /**
     * @hide
     * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
     * an argument to {@link #setDeviceVolumeBehavior(int, String, int)}.
     */
    public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
    /**
     * @hide
     * Volume behavior for an audio device where a software attenuation is applied
@@ -4647,6 +4653,18 @@ public class AudioManager {
    @Retention(RetentionPolicy.SOURCE)
    public @interface DeviceVolumeBehavior {}

    /** @hide */
    @IntDef({
            DEVICE_VOLUME_BEHAVIOR_UNSET,
            DEVICE_VOLUME_BEHAVIOR_VARIABLE,
            DEVICE_VOLUME_BEHAVIOR_FULL,
            DEVICE_VOLUME_BEHAVIOR_FIXED,
            DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
            DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface DeviceVolumeBehaviorState {}

    /**
     * @hide
     * Throws IAE on an invalid volume behavior value
@@ -4713,7 +4731,7 @@ public class AudioManager {
     * @return the volume behavior for the device
     */
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    public @DeviceVolumeBehavior int getDeviceVolumeBehavior(int deviceType,
    public @DeviceVolumeBehaviorState int getDeviceVolumeBehavior(int deviceType,
            @Nullable String deviceAddress) {
        // verify arguments
        AudioDeviceInfo.enforceValidAudioDeviceTypeOut(deviceType);
@@ -4728,8 +4746,8 @@ public class AudioManager {
     * @return the volume behavior for the device
     */
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    public @DeviceVolumeBehavior int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device)
    {
    public @DeviceVolumeBehaviorState int getDeviceVolumeBehavior(
            @NonNull AudioDeviceAttributes device) {
        // verify arguments (validity of device type is enforced in server)
        Objects.requireNonNull(device);
        // communicate with service
+157 −72
Original line number Diff line number Diff line
@@ -413,6 +413,13 @@ public class AudioService extends IAudioService.Stub
        AppOpsManager.OP_AUDIO_MEDIA_VOLUME             // STREAM_ASSISTANT
    };

    private static Set<Integer> sDeviceVolumeBehaviorSupportedDeviceOutSet = new HashSet<>(
            Arrays.asList(
                    AudioSystem.DEVICE_OUT_HDMI,
                    AudioSystem.DEVICE_OUT_HDMI_ARC,
                    AudioSystem.DEVICE_OUT_SPDIF,
                    AudioSystem.DEVICE_OUT_LINE));

    private final boolean mUseFixedVolume;

    /**
@@ -525,7 +532,6 @@ public class AudioService extends IAudioService.Stub

    // Devices for which the volume is fixed (volume is either max or muted)
    Set<Integer> mFixedVolumeDevices = new HashSet<>(Arrays.asList(
            AudioSystem.DEVICE_OUT_HDMI,
            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
            AudioSystem.DEVICE_OUT_HDMI_ARC,
@@ -929,11 +935,6 @@ public class AudioService extends IAudioService.Stub
                            AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET);
                }
                mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
                if (mHdmiPlaybackClient != null) {
                    // not a television: HDMI output will be always at max
                    mFixedVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI);
                    mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI);
                }
                mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient();
            }
        }
@@ -4049,6 +4050,11 @@ public class AudioService extends IAudioService.Stub
        }

        readVolumeGroupsSettings();

        if (DEBUG_VOL) {
            Log.d(TAG, "Restoring device volume behavior");
        }
        restoreDeviceVolumeBehavior();
    }

    /** @see AudioManager#setSpeakerphoneOn(boolean) */
@@ -4908,50 +4914,47 @@ public class AudioService extends IAudioService.Stub
        if (pkgName == null) {
            pkgName = "";
        }
        // translate Java device type to native device type (for the devices masks for full / fixed)
        final int type;
        switch (device.getType()) {
            case AudioDeviceInfo.TYPE_HDMI:
                type = AudioSystem.DEVICE_OUT_HDMI;
                break;
            case AudioDeviceInfo.TYPE_HDMI_ARC:
                type = AudioSystem.DEVICE_OUT_HDMI_ARC;
                break;
            case AudioDeviceInfo.TYPE_LINE_DIGITAL:
                type = AudioSystem.DEVICE_OUT_SPDIF;
                break;
            case AudioDeviceInfo.TYPE_AUX_LINE:
                type = AudioSystem.DEVICE_OUT_LINE;
                break;
            default:

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

        persistDeviceVolumeBehavior(audioSystemDeviceOut, deviceVolumeBehavior);
    }

    private void setDeviceVolumeBehaviorInternal(int audioSystemDeviceOut,
            @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @NonNull String caller) {
        if (!sDeviceVolumeBehaviorSupportedDeviceOutSet.contains(audioSystemDeviceOut)) {
            // unsupported for now
                throw new IllegalArgumentException("Unsupported device type " + device.getType());
            throw new IllegalArgumentException("Unsupported device type " + audioSystemDeviceOut);
        }

        // update device masks based on volume behavior
        switch (deviceVolumeBehavior) {
            case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE:
                mFullVolumeDevices.remove(type);
                mFixedVolumeDevices.remove(type);
                removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut);
                removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut);
                break;
            case AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED:
                mFullVolumeDevices.remove(type);
                mFixedVolumeDevices.add(type);
                removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut);
                addAudioSystemDeviceOutToFixedVolumeDevices(audioSystemDeviceOut);
                break;
            case AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL:
                mFullVolumeDevices.add(type);
                mFixedVolumeDevices.remove(type);
                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");
        }

        // log event and caller
        sDeviceLogger.log(new AudioEventLogger.StringEvent(
                "Volume behavior " + deviceVolumeBehavior
                        + " for dev=0x" + Integer.toHexString(type) + " by pkg:" + pkgName));
                "Volume behavior " + deviceVolumeBehavior + " for dev=0x"
                      + Integer.toHexString(audioSystemDeviceOut) + " from:" + caller));
        // make sure we have a volume entry for this device, and that volume is updated according
        // to volume behavior
        checkAddAllFixedVolumeDevices(type, "setDeviceVolumeBehavior:" + pkgName);
        checkAddAllFixedVolumeDevices(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller);
    }

    /**
@@ -4959,45 +4962,38 @@ public class AudioService extends IAudioService.Stub
     * @param device the audio output device type
     * @return the volume behavior for the device
     */
    public @AudioManager.DeviceVolumeBehavior int getDeviceVolumeBehavior(
    public @AudioManager.DeviceVolumeBehaviorState int getDeviceVolumeBehavior(
            @NonNull AudioDeviceAttributes device) {
        // verify permissions
        enforceModifyAudioRoutingPermission();

        // translate Java device type to native device type (for the devices masks for full / fixed)
        final int type;
        switch (device.getType()) {
            case AudioDeviceInfo.TYPE_HEARING_AID:
                type = AudioSystem.DEVICE_OUT_HEARING_AID;
                break;
            case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP:
                type = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
                break;
            case AudioDeviceInfo.TYPE_HDMI:
                type = AudioSystem.DEVICE_OUT_HDMI;
                break;
            case AudioDeviceInfo.TYPE_HDMI_ARC:
                type = AudioSystem.DEVICE_OUT_HDMI_ARC;
                break;
            case AudioDeviceInfo.TYPE_LINE_DIGITAL:
                type = AudioSystem.DEVICE_OUT_SPDIF;
                break;
            case AudioDeviceInfo.TYPE_AUX_LINE:
                type = AudioSystem.DEVICE_OUT_LINE;
                break;
            default:
                // unsupported for now
                throw new IllegalArgumentException("Unsupported device type " + device.getType());
        final int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice(
                device.getType());
        if (!sDeviceVolumeBehaviorSupportedDeviceOutSet.contains(audioSystemDeviceOut)
                && audioSystemDeviceOut != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
                && audioSystemDeviceOut != AudioSystem.DEVICE_OUT_HEARING_AID) {
            throw new IllegalArgumentException("Unsupported volume behavior "
                    + audioSystemDeviceOut);
        }

        int setDeviceVolumeBehavior = retrieveStoredDeviceVolumeBehavior(audioSystemDeviceOut);
        if (setDeviceVolumeBehavior != AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET) {
            return setDeviceVolumeBehavior;
        }
        if ((mFullVolumeDevices.contains(type))) {

        // setDeviceVolumeBehavior has not been explicitly called for the device type. Deduce the
        // current volume behavior.
        if ((mFullVolumeDevices.contains(audioSystemDeviceOut))) {
            return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL;
        }
        if ((mFixedVolumeDevices.contains(type))) {
        if ((mFixedVolumeDevices.contains(audioSystemDeviceOut))) {
            return AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED;
        }
        if ((mAbsVolumeMultiModeCaseDevices.contains(type))) {
        if ((mAbsVolumeMultiModeCaseDevices.contains(audioSystemDeviceOut))) {
            return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE;
        }
        if (type == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
        if (audioSystemDeviceOut == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
                && mDeviceBroker.isAvrcpAbsoluteVolumeSupported()) {
            return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE;
        }
@@ -7120,18 +7116,20 @@ public class AudioService extends IAudioService.Stub
    @GuardedBy("mHdmiClientLock")
    private void updateHdmiCecSinkLocked(boolean hdmiCecSink) {
        mHdmiCecSink = hdmiCecSink;
        if (!hasDeviceVolumeBehavior(AudioSystem.DEVICE_OUT_HDMI)) {
            if (mHdmiCecSink) {
                if (DEBUG_VOL) {
                    Log.d(TAG, "CEC sink: setting HDMI as full vol device");
                }
            mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI);
                addAudioSystemDeviceOutToFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI);
            } 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
            mFullVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI);
                removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI);
            }
        }

        checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI,
@@ -8970,4 +8968,91 @@ public class AudioService extends IAudioService.Stub
        }
        return mFullVolumeDevices.contains(deviceType);
    }

    //====================
    // Helper functions for {set,get}DeviceVolumeBehavior
    //====================
    private static String getSettingsNameForDeviceVolumeBehavior(int deviceType) {
        return "AudioService_DeviceVolumeBehavior_" + AudioSystem.getOutputDeviceName(deviceType);
    }

    private void persistDeviceVolumeBehavior(int deviceType,
            @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior) {
        if (DEBUG_VOL) {
            Log.d(TAG, "Persisting Volume Behavior for DeviceType: " + deviceType);
        }
        System.putIntForUser(mContentResolver,
                getSettingsNameForDeviceVolumeBehavior(deviceType),
                deviceVolumeBehavior,
                UserHandle.USER_CURRENT);
    }

    @AudioManager.DeviceVolumeBehaviorState
    private int retrieveStoredDeviceVolumeBehavior(int deviceType) {
        return System.getIntForUser(mContentResolver,
                getSettingsNameForDeviceVolumeBehavior(deviceType),
                AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET,
                UserHandle.USER_CURRENT);
    }

    private void restoreDeviceVolumeBehavior() {
        for (int deviceType : sDeviceVolumeBehaviorSupportedDeviceOutSet) {
            if (DEBUG_VOL) {
                Log.d(TAG, "Retrieving Volume Behavior for DeviceType: " + deviceType);
            }
            int deviceVolumeBehavior = retrieveStoredDeviceVolumeBehavior(deviceType);
            if (deviceVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET) {
                if (DEBUG_VOL) {
                    Log.d(TAG, "Skipping Setting Volume Behavior for DeviceType: " + deviceType);
                }
                continue;
            }

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

    /**
     * @param audioSystemDeviceOut one of AudioSystem.DEVICE_OUT_*
     * @return whether {@code audioSystemDeviceOut} has previously been set to a specific volume
     * behavior
     */
    private boolean hasDeviceVolumeBehavior(
            int audioSystemDeviceOut) {
        return retrieveStoredDeviceVolumeBehavior(audioSystemDeviceOut)
                != AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET;
    }

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

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

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

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