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

Commit 9c69897f authored by Yan Han's avatar Yan Han
Browse files

Show volume UI when adjusting volume with direction ADJUST_SAME

When HdmiControlService is notified by AudioService of an audio
adjustment with direction ADJUST_SAME, it sends a <Give Audio Status>
message and notifies AudioService of the response, causing it to show volume UI.

This is handled by AbsoluteVolumeAudioStatusAction. It requires
adding a boolean flag to override the default behavior of NOT notifying
AudioService of an updated audio status, if the updated audio status
didn't contain a new volume or mute state.

Bug: 293445117
Test: atest TvToAudioSystemAvbTest; manual
Change-Id: I3dc857c569f587f52f3f2f80446e84b27ad8abda
parent d0d2142c
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -32,6 +32,10 @@ final class AbsoluteVolumeAudioStatusAction extends HdmiCecFeatureAction {

    private int mInitialAudioStatusRetriesLeft = 2;

    // Flag to notify AudioService of the next audio status reported,
    // regardless of whether the audio status changed.
    private boolean mForceNextAudioStatusUpdate = false;

    private static final int STATE_WAIT_FOR_INITIAL_AUDIO_STATUS = 1;
    private static final int STATE_MONITOR_AUDIO_STATUS = 2;

@@ -70,6 +74,17 @@ final class AbsoluteVolumeAudioStatusAction extends HdmiCecFeatureAction {
        return false;
    }


    /**
     * If AVB has been enabled, send <Give Audio Status> and notify AudioService of the response.
     */
    void requestAndUpdateAudioStatus() {
        if (mState == STATE_MONITOR_AUDIO_STATUS) {
            mForceNextAudioStatusUpdate = true;
            sendGiveAudioStatus();
        }
    }

    private boolean handleReportAudioStatus(HdmiCecMessage cmd) {
        if (mTargetAddress != cmd.getSource() || cmd.getParams().length == 0) {
            return false;
@@ -89,12 +104,15 @@ final class AbsoluteVolumeAudioStatusAction extends HdmiCecFeatureAction {
            localDevice().getService().enableAbsoluteVolumeBehavior(audioStatus);
            mState = STATE_MONITOR_AUDIO_STATUS;
        } else if (mState == STATE_MONITOR_AUDIO_STATUS) {
            if (audioStatus.getVolume() != mLastAudioStatus.getVolume()) {
            if (mForceNextAudioStatusUpdate
                    || audioStatus.getVolume() != mLastAudioStatus.getVolume()) {
                localDevice().getService().notifyAvbVolumeChange(audioStatus.getVolume());
            }
            if (audioStatus.getMute() != mLastAudioStatus.getMute()) {
            if (mForceNextAudioStatusUpdate
                    || audioStatus.getMute() != mLastAudioStatus.getMute()) {
                localDevice().getService().notifyAvbMuteChange(audioStatus.getMute());
            }
            mForceNextAudioStatusUpdate = false;
        }
        mLastAudioStatus = audioStatus;

+13 −0
Original line number Diff line number Diff line
@@ -1047,6 +1047,19 @@ abstract class HdmiCecLocalDevice extends HdmiLocalDevice {
        }
    }

    /**
     * If AVB has been enabled, request the System Audio device's audio status and notify
     * AudioService of its response.
     */
    @ServiceThreadOnly
    void requestAndUpdateAvbAudioStatus() {
        assertRunOnServiceThread();
        for (AbsoluteVolumeAudioStatusAction action :
                getActions(AbsoluteVolumeAudioStatusAction.class)) {
            action.requestAndUpdateAudioStatus();
        }
    }

    /**
     * Determines whether {@code targetAddress} supports <Set Audio Volume Level>. Does two things
     * in parallel: send <Give Features> (to get <Report Features> in response),
+7 −0
Original line number Diff line number Diff line
@@ -4646,6 +4646,13 @@ public class HdmiControlService extends SystemService {
                    // same keycode for all three mute options.
                    keyCode = KeyEvent.KEYCODE_VOLUME_MUTE;
                    break;
                case AudioManager.ADJUST_SAME:
                    // Query the current audio status of the Audio System and display UI for it
                    // Only for TVs, because Playback devices don't display UI when using AVB
                    if (tv() != null) {
                        tv().requestAndUpdateAvbAudioStatus();
                    }
                    return;
                default:
                    return;
            }
+5 −3
Original line number Diff line number Diff line
@@ -92,11 +92,11 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {

    // Default Audio Status given by the System Audio device in its initial <Report Audio Status>
    // that triggers AVB being enabled
    private static final AudioStatus INITIAL_SYSTEM_AUDIO_DEVICE_STATUS =
    protected static final AudioStatus INITIAL_SYSTEM_AUDIO_DEVICE_STATUS =
            new AudioStatus(50, false);

    // VolumeInfo passed to AudioDeviceVolumeManager#setDeviceAbsoluteVolumeBehavior to enable AVB
    private static final VolumeInfo ENABLE_AVB_VOLUME_INFO =
    protected static final VolumeInfo ENABLE_AVB_VOLUME_INFO =
            new VolumeInfo.Builder(AudioManager.STREAM_MUSIC)
                    .setMuted(INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getMute())
                    .setVolumeIndex(INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume())
@@ -106,6 +106,8 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {

    private static final int EMPTY_FLAGS = 0;

    protected static final int STREAM_MUSIC_MAX_VOLUME = 25;

    protected abstract HdmiCecLocalDevice createLocalDevice(HdmiControlService hdmiControlService);

    protected abstract int getPhysicalAddress();
@@ -201,7 +203,7 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
                Collections.singletonList(getAudioOutputDevice()));

        // Max volume of STREAM_MUSIC
        mAudioFramework.setStreamMaxVolume(AudioManager.STREAM_MUSIC, 25);
        mAudioFramework.setStreamMaxVolume(AudioManager.STREAM_MUSIC, STREAM_MUSIC_MAX_VOLUME);

        // Receive messages from devices to make sure they're registered in HdmiCecNetwork
        mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+94 −0
Original line number Diff line number Diff line
@@ -321,4 +321,98 @@ public class TvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehaviorTest {
                        getLogicalAddress(), getSystemAudioDeviceLogicalAddress(),
                        Constants.AUDIO_VOLUME_STATUS_UNKNOWN));
    }

    /**
     * Tests that a volume adjustment command with direction ADJUST_SAME causes HdmiControlService
     * to request the System Audio device's audio status, and notify AudioService of the
     * audio status.
     */
    @Test
    public void avbEnabled_audioDeviceVolumeAdjusted_adjustSame_updatesAudioService() {
        enableAbsoluteVolumeBehavior();
        mNativeWrapper.clearResultMessages();

        // HdmiControlService receives a volume adjustment with direction ADJUST_SAME
        mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeAdjusted(
                getAudioOutputDevice(),
                ENABLE_AVB_VOLUME_INFO,
                AudioManager.ADJUST_SAME,
                AudioDeviceVolumeManager.ADJUST_MODE_NORMAL
        );
        mTestLooper.dispatchAll();

        // Device sends <Give Audio Status>
        assertThat(mNativeWrapper.getResultMessages()).contains(
                HdmiCecMessageBuilder.buildGiveAudioStatus(getLogicalAddress(),
                        getSystemAudioDeviceLogicalAddress()));

        clearInvocations(mAudioManager);

        // Device receives <Report Audio Status> with a new volume and mute state
        mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildReportAudioStatus(
                getSystemAudioDeviceLogicalAddress(),
                getLogicalAddress(),
                80,
                true));
        mTestLooper.dispatchAll();

        // HdmiControlService calls setStreamVolume and adjustStreamVolume to trigger volume UI
        verify(mAudioManager).setStreamVolume(
                eq(AudioManager.STREAM_MUSIC),
                // Volume level is rescaled to the max volume of STREAM_MUSIC
                eq(80 * STREAM_MUSIC_MAX_VOLUME / AudioStatus.MAX_VOLUME),
                eq(AudioManager.FLAG_ABSOLUTE_VOLUME | AudioManager.FLAG_SHOW_UI));
        verify(mAudioManager).adjustStreamVolume(
                eq(AudioManager.STREAM_MUSIC),
                eq(AudioManager.ADJUST_MUTE),
                eq(AudioManager.FLAG_ABSOLUTE_VOLUME | AudioManager.FLAG_SHOW_UI));
    }

    /**
     * Tests that a volume adjustment command with direction ADJUST_SAME causes HdmiControlService
     * to request the System Audio device's audio status, and notify AudioService of the
     * audio status, even if it's unchanged from the previous one.
     */
    @Test
    public void avbEnabled_audioDeviceVolumeAdjusted_adjustSame_noChange_updatesAudioService() {
        enableAbsoluteVolumeBehavior();
        mNativeWrapper.clearResultMessages();

        // HdmiControlService receives a volume adjustment with direction ADJUST_SAME
        mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeAdjusted(
                getAudioOutputDevice(),
                ENABLE_AVB_VOLUME_INFO,
                AudioManager.ADJUST_SAME,
                AudioDeviceVolumeManager.ADJUST_MODE_NORMAL
        );
        mTestLooper.dispatchAll();

        // Device sends <Give Audio Status>
        assertThat(mNativeWrapper.getResultMessages()).contains(
                HdmiCecMessageBuilder.buildGiveAudioStatus(getLogicalAddress(),
                        getSystemAudioDeviceLogicalAddress()));

        clearInvocations(mAudioManager);

        // Device receives <Report Audio Status> with the same volume level and mute state that
        // as when AVB was enabled
        mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildReportAudioStatus(
                getSystemAudioDeviceLogicalAddress(),
                getLogicalAddress(),
                INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume(),
                INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getMute()));
        mTestLooper.dispatchAll();

        // HdmiControlService calls setStreamVolume and adjustStreamVolume to trigger volume UI
        verify(mAudioManager).setStreamVolume(
                eq(AudioManager.STREAM_MUSIC),
                // Volume level is rescaled to the max volume of STREAM_MUSIC
                eq(INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume()
                        * STREAM_MUSIC_MAX_VOLUME / AudioStatus.MAX_VOLUME),
                eq(AudioManager.FLAG_ABSOLUTE_VOLUME | AudioManager.FLAG_SHOW_UI));
        verify(mAudioManager).adjustStreamVolume(
                eq(AudioManager.STREAM_MUSIC),
                eq(AudioManager.ADJUST_UNMUTE),
                eq(AudioManager.FLAG_ABSOLUTE_VOLUME | AudioManager.FLAG_SHOW_UI));
    }
}