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

Commit 3b2a6acd authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "AudioManager: set/get audio device volume behavior" into rvc-dev am:...

Merge "AudioManager: set/get audio device volume behavior" into rvc-dev am: e9ffff37 am: 902a2df6

Change-Id: I83a519644dc975c70a1f62ce6ebcdb8055125eba
parents 6272b649 902a2df6
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -99,11 +99,11 @@ public final class AudioDeviceAttributes implements Parcelable {
        if (role != ROLE_OUTPUT && role != ROLE_INPUT) {
            throw new IllegalArgumentException("Invalid role " + role);
        }
        if (role == ROLE_OUTPUT && !AudioDeviceInfo.isValidAudioDeviceTypeOut(type)) {
            throw new IllegalArgumentException("Invalid output device type " + type);
        if (role == ROLE_OUTPUT) {
            AudioDeviceInfo.enforceValidAudioDeviceTypeOut(type);
        }
        if (role == ROLE_INPUT && !AudioDeviceInfo.isValidAudioDeviceTypeIn(type)) {
            throw new IllegalArgumentException("Invalid input device type " + type);
        if (role == ROLE_INPUT) {
            AudioDeviceInfo.enforceValidAudioDeviceTypeIn(type);
        }

        mRole = role;
+22 −0
Original line number Diff line number Diff line
@@ -280,6 +280,28 @@ public final class AudioDeviceInfo {
        }
    }

    /**
     * @hide
     * Throws IAE on an invalid output device type
     * @param type
     */
    public static void enforceValidAudioDeviceTypeOut(int type) {
        if (!isValidAudioDeviceTypeOut(type)) {
            throw new IllegalArgumentException("Illegal output device type " + type);
        }
    }

    /**
     * @hide
     * Throws IAE on an invalid input device type
     * @param type
     */
    public static void enforceValidAudioDeviceTypeIn(int type) {
        if (!isValidAudioDeviceTypeIn(type)) {
            throw new IllegalArgumentException("Illegal input device type " + type);
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
+144 −0
Original line number Diff line number Diff line
@@ -4571,6 +4571,150 @@ public class AudioManager {
        }
    }

    /**
     * @hide
     * Volume behavior for an audio device where a software attenuation is applied
     * @see #setDeviceVolumeBehavior(int, String, int)
     */
    public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
    /**
     * @hide
     * Volume behavior for an audio device where the volume is always set to provide no attenuation
     *     nor gain (e.g. unit gain).
     * @see #setDeviceVolumeBehavior(int, String, int)
     */
    public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
    /**
     * @hide
     * Volume behavior for an audio device where the volume is either set to muted, or to provide
     *     no attenuation nor gain (e.g. unit gain).
     * @see #setDeviceVolumeBehavior(int, String, int)
     */
    public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
    /**
     * @hide
     * Volume behavior for an audio device where no software attenuation is applied, and
     *     the volume is kept synchronized between the host and the device itself through a
     *     device-specific protocol such as BT AVRCP.
     * @see #setDeviceVolumeBehavior(int, String, int)
     */
    public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
    /**
     * @hide
     * Volume behavior for an audio device where no software attenuation is applied, and
     *     the volume is kept synchronized between the host and the device itself through a
     *     device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
     *     normal vs in phone call).
     * @see #setMode(int)
     * @see #setDeviceVolumeBehavior(int, String, int)
     */
    public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;

    /** @hide */
    @IntDef({
            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 DeviceVolumeBehavior {}

    /**
     * @hide
     * Throws IAE on an invalid volume behavior value
     * @param volumeBehavior behavior value to check
     */
    public static void enforceValidVolumeBehavior(int volumeBehavior) {
        switch (volumeBehavior) {
            case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
            case DEVICE_VOLUME_BEHAVIOR_FULL:
            case DEVICE_VOLUME_BEHAVIOR_FIXED:
            case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
            case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
                return;
            default:
                throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
        }
    }

    /**
     * @hide
     * Sets the volume behavior for an audio output device.
     * @param deviceType the type of audio device to be affected. Currently only supports
     *     {@link AudioDeviceInfo#TYPE_HDMI}, {@link AudioDeviceInfo#TYPE_HDMI_ARC},
     *     {@link AudioDeviceInfo#TYPE_LINE_DIGITAL} and {@link AudioDeviceInfo#TYPE_AUX_LINE}
     * @param deviceAddress the address of the device, if any
     * @param deviceVolumeBehavior one of the device behaviors
     */
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    public void setDeviceVolumeBehavior(int deviceType, @Nullable String deviceAddress,
            @DeviceVolumeBehavior int deviceVolumeBehavior) {
        setDeviceVolumeBehavior(new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
                deviceType, deviceAddress), deviceVolumeBehavior);
    }

    /**
     * @hide
     * Sets the volume behavior for an audio output device.
     * @param device the device to be affected. Currently only supports devices of type
     *     {@link AudioDeviceInfo#TYPE_HDMI}, {@link AudioDeviceInfo#TYPE_HDMI_ARC},
     *     {@link AudioDeviceInfo#TYPE_LINE_DIGITAL} and {@link AudioDeviceInfo#TYPE_AUX_LINE}
     * @param deviceVolumeBehavior one of the device behaviors
     */
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
            @DeviceVolumeBehavior int deviceVolumeBehavior) {
        // verify arguments (validity of device type is enforced in server)
        Objects.requireNonNull(device);
        enforceValidVolumeBehavior(deviceVolumeBehavior);
        // communicate with service
        final IAudioService service = getService();
        try {
            service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
                    mApplicationContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * @hide
     * Returns the volume device behavior for the given device type and address
     * @param deviceType an audio output device type, as defined in {@link AudioDeviceInfo}
     * @param deviceAddress the address of the audio device, if any.
     * @return the volume behavior for the device
     */
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    public @DeviceVolumeBehavior int getDeviceVolumeBehavior(int deviceType,
            @Nullable String deviceAddress) {
        // verify arguments
        AudioDeviceInfo.enforceValidAudioDeviceTypeOut(deviceType);
        return getDeviceVolumeBehavior(new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
                deviceType, deviceAddress));
    }

    /**
     * @hide
     * Returns the volume device behavior for the given audio device
     * @param device the audio device
     * @return the volume behavior for the device
     */
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    public @DeviceVolumeBehavior int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device)
    {
        // verify arguments (validity of device type is enforced in server)
        Objects.requireNonNull(device);
        // communicate with service
        final IAudioService service = getService();
        try {
            return service.getDeviceVolumeBehavior(device);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

     /**
     * Indicate wired accessory connection state change.
     * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
+5 −0
Original line number Diff line number Diff line
@@ -294,6 +294,11 @@ interface IAudioService {

    oneway void setRttEnabled(in boolean rttEnabled);

    void setDeviceVolumeBehavior(in AudioDeviceAttributes device,
             in int deviceVolumeBehavior, in String pkgName);

    int getDeviceVolumeBehavior(in AudioDeviceAttributes device);

    // WARNING: read warning at top of file, new methods that need to be used by native
    // code via IAudioManager.h need to be added to the top section.
}
+112 −2
Original line number Diff line number Diff line
@@ -2332,8 +2332,7 @@ public class AudioService extends IAudioService.Stub
    }

    private void enforceModifyAudioRoutingPermission() {
        if (mContext.checkCallingOrSelfPermission(
                android.Manifest.permission.MODIFY_AUDIO_ROUTING)
        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
                != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Missing MODIFY_AUDIO_ROUTING permission");
        }
@@ -4610,6 +4609,117 @@ public class AudioService extends IAudioService.Stub
        observeDevicesForStreams(-1);
    }

    /**
     * @see AudioManager#setDeviceVolumeBehavior(AudioDeviceAttributes, int)
     * @param device the audio device to be affected
     * @param deviceVolumeBehavior one of the device behaviors
     */
    public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
            @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @Nullable String pkgName) {
        // verify permissions
        enforceModifyAudioRoutingPermission();
        // verify arguments
        Objects.requireNonNull(device);
        AudioManager.enforceValidVolumeBehavior(deviceVolumeBehavior);
        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:
                // unsupported for now
                throw new IllegalArgumentException("Unsupported device type " + device.getType());
        }
        // update device masks based on volume behavior
        switch (deviceVolumeBehavior) {
            case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE:
                mFullVolumeDevices.remove(type);
                mFixedVolumeDevices.remove(type);
                break;
            case AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED:
                mFullVolumeDevices.remove(type);
                mFixedVolumeDevices.add(type);
                break;
            case AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL:
                mFullVolumeDevices.add(type);
                mFixedVolumeDevices.remove(type);
                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));
        // make sure we have a volume entry for this device, and that volume is updated according
        // to volume behavior
        checkAddAllFixedVolumeDevices(type, "setDeviceVolumeBehavior:" + pkgName);
    }

    /**
     * @see AudioManager#getDeviceVolumeBehavior(AudioDeviceAttributes)
     * @param device the audio output device type
     * @return the volume behavior for the device
     */
    public @AudioManager.DeviceVolumeBehavior 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());
        }
        if ((mFullVolumeDevices.contains(type))) {
            return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL;
        }
        if ((mFixedVolumeDevices.contains(type))) {
            return AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED;
        }
        if ((mAbsVolumeMultiModeCaseDevices.contains(type))) {
            return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE;
        }
        if (type == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
                && mDeviceBroker.isAvrcpAbsoluteVolumeSupported()) {
            return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE;
        }
        return AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE;
    }

    /*package*/ static final int CONNECTION_STATE_DISCONNECTED = 0;
    /*package*/ static final int CONNECTION_STATE_CONNECTED = 1;
    /**