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

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

Merge changes from topic "adjust-only-avb" into udc-dev

* changes:
  Check for feature flag for numeric volume UI
  Implement soundbar volume UI for TV panels.
  Add wrapper for AudioManager, allowing it to be faked in tests
  Rename "Absolute Volume Control" to "absolute volume behavior"
  Fix system server crash on receiving <Report Audio Status>
parents b6426114 7298a68a
Loading
Loading
Loading
Loading
+18 −8
Original line number Diff line number Diff line
@@ -17,11 +17,14 @@
package com.android.server.hdmi;

/**
 * Action to query and track the audio status of the System Audio device when enabling or using
 * Absolute Volume Control. Must be removed when AVC is disabled. Performs two main functions:
 * 1. When enabling AVC: queries the starting audio status of the System Audio device and
 *    enables the feature upon receiving a response.
 * 2. While AVC is enabled: monitors <Report Audio Status> messages from the System Audio device and
 * Action to query and track the audio status of the System Audio device when using
 * absolute volume behavior, or adjust-only absolute volume behavior. Must be removed when
 * neither behavior is used.
 *
 * Performs two main functions:
 * 1. When enabling AVB: queries the starting audio status of the System Audio device and
 *    adopts the appropriate volume behavior upon receiving a response.
 * 2. While AVB is enabled: monitors <Report Audio Status> messages from the System Audio device and
 *    notifies AudioService if the audio status changes.
 */
final class AbsoluteVolumeAudioStatusAction extends HdmiCecFeatureAction {
@@ -74,16 +77,23 @@ final class AbsoluteVolumeAudioStatusAction extends HdmiCecFeatureAction {

        boolean mute = HdmiUtils.isAudioStatusMute(cmd);
        int volume = HdmiUtils.getAudioStatusVolume(cmd);

        // If the volume is out of range, report it as handled and ignore the message.
        // According to the spec, such values are either reserved or indicate an unknown volume.
        if (volume == Constants.UNKNOWN_VOLUME) {
            return true;
        }

        AudioStatus audioStatus = new AudioStatus(volume, mute);
        if (mState == STATE_WAIT_FOR_INITIAL_AUDIO_STATUS) {
            localDevice().getService().enableAbsoluteVolumeControl(audioStatus);
            localDevice().getService().enableAbsoluteVolumeBehavior(audioStatus);
            mState = STATE_MONITOR_AUDIO_STATUS;
        } else if (mState == STATE_MONITOR_AUDIO_STATUS) {
            if (audioStatus.getVolume() != mLastAudioStatus.getVolume()) {
                localDevice().getService().notifyAvcVolumeChange(audioStatus.getVolume());
                localDevice().getService().notifyAvbVolumeChange(audioStatus.getVolume());
            }
            if (audioStatus.getMute() != mLastAudioStatus.getMute()) {
                localDevice().getService().notifyAvcMuteChange(audioStatus.getMute());
                localDevice().getService().notifyAvbMuteChange(audioStatus.getMute());
            }
        }
        mLastAudioStatus = audioStatus;
+37 −29
Original line number Diff line number Diff line
@@ -16,9 +16,11 @@

package com.android.server.hdmi;

import static android.media.AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener;
import static android.media.AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener;

import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.content.Context;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceVolumeManager;
import android.media.VolumeInfo;
@@ -26,42 +28,48 @@ import android.media.VolumeInfo;
import java.util.concurrent.Executor;

/**
 * Wrapper for {@link AudioDeviceVolumeManager}. Creates an instance of the class and directly
 * passes method calls to that instance.
 * Interface with the methods from {@link AudioDeviceVolumeManager} used by the HDMI framework.
 * Allows the class to be faked for tests.
 *
 * See implementations {@link DefaultAudioDeviceVolumeManagerWrapper} and
 * {@link FakeAudioFramework.FakeAudioDeviceVolumeManagerWrapper}.
 */
public class AudioDeviceVolumeManagerWrapper
        implements AudioDeviceVolumeManagerWrapperInterface {

    private static final String TAG = "AudioDeviceVolumeManagerWrapper";
public interface AudioDeviceVolumeManagerWrapper {

    private final AudioDeviceVolumeManager mAudioDeviceVolumeManager;
    /**
     * Wrapper for {@link AudioDeviceVolumeManager#addOnDeviceVolumeBehaviorChangedListener(
     * Executor, OnDeviceVolumeBehaviorChangedListener)}
     */
    void addOnDeviceVolumeBehaviorChangedListener(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener);

    public AudioDeviceVolumeManagerWrapper(Context context) {
        mAudioDeviceVolumeManager = new AudioDeviceVolumeManager(context);
    }
    /**
     * Wrapper for {@link AudioDeviceVolumeManager#removeOnDeviceVolumeBehaviorChangedListener(
     * OnDeviceVolumeBehaviorChangedListener)}
     */
    void removeOnDeviceVolumeBehaviorChangedListener(
            @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener);

    @Override
    public void addOnDeviceVolumeBehaviorChangedListener(
    /**
     * Wrapper for {@link AudioDeviceVolumeManager#setDeviceAbsoluteVolumeBehavior(
     * AudioDeviceAttributes, VolumeInfo, Executor, OnAudioDeviceVolumeChangedListener, boolean)}
     */
    void setDeviceAbsoluteVolumeBehavior(
            @NonNull AudioDeviceAttributes device,
            @NonNull VolumeInfo volume,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener)
            throws SecurityException {
        mAudioDeviceVolumeManager.addOnDeviceVolumeBehaviorChangedListener(executor, listener);
    }

    @Override
    public void removeOnDeviceVolumeBehaviorChangedListener(
            @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener) {
        mAudioDeviceVolumeManager.removeOnDeviceVolumeBehaviorChangedListener(listener);
    }
            @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener,
            boolean handlesVolumeAdjustment);

    @Override
    public void setDeviceAbsoluteVolumeBehavior(
    /**
     * Wrapper for {@link AudioDeviceVolumeManager#setDeviceAbsoluteVolumeAdjustOnlyBehavior(
     * AudioDeviceAttributes, VolumeInfo, Executor, OnAudioDeviceVolumeChangedListener, boolean)}
     */
    void setDeviceAbsoluteVolumeAdjustOnlyBehavior(
            @NonNull AudioDeviceAttributes device,
            @NonNull VolumeInfo volume,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener,
            boolean handlesVolumeAdjustment) {
        mAudioDeviceVolumeManager.setDeviceAbsoluteVolumeBehavior(device, volume, executor,
                vclistener, handlesVolumeAdjustment);
    }
            boolean handlesVolumeAdjustment);
}
+0 −61
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 com.android.server.hdmi;

import static android.media.AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener;
import static android.media.AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener;

import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceVolumeManager;
import android.media.VolumeInfo;

import java.util.concurrent.Executor;

/**
 * Interface with the methods from {@link AudioDeviceVolumeManager} used by the HDMI framework.
 * Allows the class to be faked for tests.
 */
public interface AudioDeviceVolumeManagerWrapperInterface {

    /**
     * Wrapper for {@link AudioDeviceVolumeManager#addOnDeviceVolumeBehaviorChangedListener(
     * Executor, OnDeviceVolumeBehaviorChangedListener)}
     */
    void addOnDeviceVolumeBehaviorChangedListener(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener);

    /**
     * Wrapper for {@link AudioDeviceVolumeManager#removeOnDeviceVolumeBehaviorChangedListener(
     * OnDeviceVolumeBehaviorChangedListener)}
     */
    void removeOnDeviceVolumeBehaviorChangedListener(
            @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener);

    /**
     * Wrapper for {@link AudioDeviceVolumeManager#setDeviceAbsoluteVolumeBehavior(
     * AudioDeviceAttributes, VolumeInfo, Executor, OnAudioDeviceVolumeChangedListener, boolean)}
     */
    void setDeviceAbsoluteVolumeBehavior(
            @NonNull AudioDeviceAttributes device,
            @NonNull VolumeInfo volume,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener,
            boolean handlesVolumeAdjustment);
}
+105 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 com.android.server.hdmi;

import android.annotation.NonNull;
import android.media.AudioAttributes;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceVolumeManager;
import android.media.AudioManager;

import java.util.List;

/**
 * Interface with the methods from {@link AudioDeviceVolumeManager} used by the HDMI control
 * framework. Allows the class to be faked for tests.
 *
 * See implementations {@link DefaultAudioManagerWrapper} and
 * {@link FakeAudioFramework.FakeAudioManagerWrapper}.
 */
public interface AudioManagerWrapper {

    /**
     * Wraps {@link AudioManager#adjustStreamVolume(int, int, int)}
     */
    void adjustStreamVolume(int streamType, int direction,
            @AudioManager.PublicVolumeFlags int flags);

    /**
     * Wraps {@link AudioManager#setStreamVolume(int, int, int)}
     */
    void setStreamVolume(int streamType, int index, @AudioManager.PublicVolumeFlags int flags);

    /**
     * Wraps {@link AudioManager#getStreamVolume(int)}
     */
    int getStreamVolume(int streamType);

    /**
     * Wraps {@link AudioManager#getStreamMinVolume(int)}
     */
    int getStreamMinVolume(int streamType);

    /**
     * Wraps {@link AudioManager#getStreamMaxVolume(int)}
     */
    int getStreamMaxVolume(int streamType);

    /**
     * Wraps {@link AudioManager#isStreamMute(int)}
     */
    boolean isStreamMute(int streamType);

    /**
     * Wraps {@link AudioManager#setStreamMute(int, boolean)}
     */
    void setStreamMute(int streamType, boolean state);

    /**
     * Wraps {@link AudioManager#setHdmiSystemAudioSupported(boolean)}
     */
    int setHdmiSystemAudioSupported(boolean on);

    /**
     * Wraps {@link AudioManager#setWiredDeviceConnectionState(AudioDeviceAttributes, int)}
     */
    void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state);

    /**
     * Wraps {@link AudioManager#setWiredDeviceConnectionState(int, int, String, String)}
     */
    void setWiredDeviceConnectionState(int device, int state, String address, String name);

    /**
     * Wraps {@link AudioManager#getDeviceVolumeBehavior(AudioDeviceAttributes)}
     */
    @AudioManager.DeviceVolumeBehavior
    int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device);

    /**
     * Wraps {@link AudioManager#setDeviceVolumeBehavior(AudioDeviceAttributes, int)}
     */
    void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
            @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior);

    /**
     * Wraps {@link AudioManager#getDevicesForAttributes(AudioAttributes)}
     */
    @NonNull
    List<AudioDeviceAttributes> getDevicesForAttributes(
            @NonNull AudioAttributes attributes);
}
+3 −1
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import java.util.Objects;
/**
 * Immutable representation of the information in the [Audio Status] operand:
 * volume status (0 <= N <= 100) and mute status (muted or unmuted).
 * The volume level is limited to the range [0, 100] upon construction.
 * This object cannot represent an audio status where the volume is unknown, or out of bounds.
 */
public class AudioStatus {
    public static final int MAX_VOLUME = 100;
@@ -32,7 +34,7 @@ public class AudioStatus {
    boolean mMute;

    public AudioStatus(int volume, boolean mute) {
        mVolume = volume;
        mVolume = Math.max(Math.min(volume, MAX_VOLUME), MIN_VOLUME);
        mMute = mute;
    }

Loading