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

Commit 9b91e8c5 authored by Amy's avatar Amy Committed by Amy Zhang
Browse files

Add system audio mode related handlers.

Test: atest com.android.server.hdmi
Change-Id: I4fd10ceb9e8a5951584f3917dc267a04091049cf
(cherry picked from commit 714cd0383c639613aa21eabfe3e20bb3b7386244)
parent 8e63b746
Loading
Loading
Loading
Loading
+88 −0
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.hdmi;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.media.AudioManager;
import android.media.AudioManager;
import android.os.SystemProperties;
import android.os.SystemProperties;
import android.provider.Settings.Global;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;


@@ -34,8 +35,16 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice {
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private boolean mSystemAudioActivated;
    private boolean mSystemAudioActivated;


    // Whether the System Audio Control feature is enabled or not. True by default.
    @GuardedBy("mLock")
    private boolean mSystemAudioControlFeatureEnabled;

    protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
    protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
        super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
        super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
        mSystemAudioControlFeatureEnabled = true;
        // TODO(amyjojo) make System Audio Control controllable by users
        /*mSystemAudioControlFeatureEnabled =
            mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);*/
    }
    }


    @Override
    @Override
@@ -151,6 +160,55 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice {
        return true;
        return true;
    }
    }


    @Override
    @ServiceThreadOnly
    protected boolean handleSystemAudioModeRequest(HdmiCecMessage message) {
        assertRunOnServiceThread();
        boolean systemAudioStatusOn = message.getParams().length != 0;
        if (!setSystemAudioMode(systemAudioStatusOn)) {
            mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
            return true;
        }

        if (systemAudioStatusOn) {
            // TODO(amyjojo): Bring up device when it's on standby mode

            // TODO(amyjojo): Switch to the corresponding input

        }
        // Mute device when feature is turned off and unmute device when feature is turned on
        boolean currentMuteStatus =
            mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC);
        if (currentMuteStatus == systemAudioStatusOn) {
            mService.getAudioManager().adjustStreamVolume(AudioManager.STREAM_MUSIC,
                systemAudioStatusOn ? AudioManager.ADJUST_UNMUTE : AudioManager.ADJUST_MUTE, 0);
        }

        mService.sendCecCommand(HdmiCecMessageBuilder
            .buildSetSystemAudioMode(mAddress, Constants.ADDR_BROADCAST, systemAudioStatusOn));
        return true;
    }

    @Override
    @ServiceThreadOnly
    protected boolean handleSetSystemAudioMode(HdmiCecMessage message) {
        assertRunOnServiceThread();
        if (!setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message))) {
            mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
        }
        return true;
    }

    @Override
    @ServiceThreadOnly
    protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) {
        assertRunOnServiceThread();
        if (!setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message))) {
            mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
        }
        return true;
    }

    private void reportAudioStatus(HdmiCecMessage message) {
    private void reportAudioStatus(HdmiCecMessage message) {
        assertRunOnServiceThread();
        assertRunOnServiceThread();


@@ -162,4 +220,34 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice {
        mService.sendCecCommand(HdmiCecMessageBuilder
        mService.sendCecCommand(HdmiCecMessageBuilder
            .buildReportAudioStatus(mAddress, message.getSource(), scaledVolume, mute));
            .buildReportAudioStatus(mAddress, message.getSource(), scaledVolume, mute));
    }
    }

    protected boolean setSystemAudioMode(boolean newSystemAudioMode) {
        if (!isSystemAudioControlFeatureEnabled()) {
            HdmiLogger.debug("Cannot turn " +
                (newSystemAudioMode ? "on" : "off") + "system audio mode " +
                "because the System Audio Control feature is disabled.");
            return false;
        }
        HdmiLogger.debug("System Audio Mode change[old:%b new:%b]",
            mSystemAudioActivated, newSystemAudioMode);
        updateAudioManagerForSystemAudio(newSystemAudioMode);
        synchronized (mLock) {
            if (mSystemAudioActivated != newSystemAudioMode) {
                mSystemAudioActivated = newSystemAudioMode;
                mService.announceSystemAudioModeChange(newSystemAudioMode);
            }
        }
        return true;
    }

    private void updateAudioManagerForSystemAudio(boolean on) {
        int device = mService.getAudioManager().setHdmiSystemAudioSupported(on);
        HdmiLogger.debug("[A]UpdateSystemAudio mode[on=%b] output=[%X]", on, device);
    }

    protected boolean isSystemAudioControlFeatureEnabled() {
        synchronized (mLock) {
            return mSystemAudioControlFeatureEnabled;
        }
    }
}
}
+113 −22
Original line number Original line Diff line number Diff line
@@ -16,8 +16,10 @@
package com.android.server.hdmi;
package com.android.server.hdmi;


import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertEquals;


@@ -44,6 +46,8 @@ public class HdmiCecLocalDeviceAudioSystemTest {


    private static final class NativeWrapperImpl implements NativeWrapper {
    private static final class NativeWrapperImpl implements NativeWrapper {


        private HdmiCecMessage mResultMessage;

        @Override
        @Override
        public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) {
        public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) {
            return 1L;
            return 1L;
@@ -52,6 +56,9 @@ public class HdmiCecLocalDeviceAudioSystemTest {
        @Override
        @Override
        public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress,
        public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress,
            byte[] body) {
            byte[] body) {
            if (body.length != 0) {
                mResultMessage = HdmiCecMessageBuilder.of(srcAddress, dstAddress, body);
            }
            return 1;
            return 1;
        }
        }


@@ -106,12 +113,16 @@ public class HdmiCecLocalDeviceAudioSystemTest {
        public boolean nativeIsConnected(long controllerPtr, int port) {
        public boolean nativeIsConnected(long controllerPtr, int port) {
            return false;
            return false;
        }
        }

        public HdmiCecMessage getResultMessage() {
            return mResultMessage;
        }
    }
    }


    private HdmiControlService mHdmiControlService;
    private HdmiControlService mHdmiControlService;
    private HdmiCecController mHdmiCecController;
    private HdmiCecController mHdmiCecController;
    private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
    private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
    private HdmiCecMessage mResultMessage;
    private NativeWrapperImpl mNativeWrapper;
    private Looper mMyLooper;
    private Looper mMyLooper;
    private TestLooper mTestLooper = new TestLooper();
    private TestLooper mTestLooper = new TestLooper();
    private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
    private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
@@ -154,12 +165,20 @@ public class HdmiCecLocalDeviceAudioSystemTest {
                                return 100;
                                return 100;
                        }
                        }
                    }
                    }
                };
            }


                    @Override
                    @Override
            void sendCecCommand(HdmiCecMessage command) {
                    public void adjustStreamVolume(int streamType, int direction, int flags) {
                mResultMessage = command;
                        switch (streamType) {
                            case STREAM_MUSIC:
                                if (direction == AudioManager.ADJUST_UNMUTE) {
                                    mMusicMute = false;
                                } else if (direction == AudioManager.ADJUST_MUTE) {
                                    mMusicMute = true;
                                }
                            default:
                        }
                    }
                };
            }
            }
        };
        };
        mMyLooper = mTestLooper.getLooper();
        mMyLooper = mTestLooper.getLooper();
@@ -167,10 +186,12 @@ public class HdmiCecLocalDeviceAudioSystemTest {
        mHdmiCecLocalDeviceAudioSystem.init();
        mHdmiCecLocalDeviceAudioSystem.init();
        mHdmiControlService.setIoLooper(mMyLooper);
        mHdmiControlService.setIoLooper(mMyLooper);


        mNativeWrapper = new NativeWrapperImpl();
        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
            mHdmiControlService, new NativeWrapperImpl());
            mHdmiControlService, mNativeWrapper);
        mHdmiControlService.setCecController(mHdmiCecController);
        mHdmiControlService.setCecController(mHdmiCecController);
        mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
        mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));


        mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
        mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
        mHdmiControlService.initPortInfo();
        mHdmiControlService.initPortInfo();
@@ -187,24 +208,24 @@ public class HdmiCecLocalDeviceAudioSystemTest {
        int scaledVolume = VolumeControlAction.scaleToCecVolume(10, mMusicMaxVolume);
        int scaledVolume = VolumeControlAction.scaleToCecVolume(10, mMusicMaxVolume);
        HdmiCecMessage expectMessage = HdmiCecMessageBuilder.buildReportAudioStatus(
        HdmiCecMessage expectMessage = HdmiCecMessageBuilder.buildReportAudioStatus(
            ADDR_AUDIO_SYSTEM, ADDR_TV, scaledVolume, true);
            ADDR_AUDIO_SYSTEM, ADDR_TV, scaledVolume, true);

        HdmiCecMessage messageGive = HdmiCecMessageBuilder.buildGiveAudioStatus(
        HdmiCecMessage message = HdmiCecMessageBuilder.buildGiveAudioStatus(
            ADDR_TV, ADDR_AUDIO_SYSTEM);
            ADDR_TV, ADDR_AUDIO_SYSTEM);
        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(message));


        assertTrue(mResultMessage.equals(expectMessage));
        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(messageGive));
        mTestLooper.dispatchAll();
        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
    }
    }


    @Test
    @Test
    public void handleGiveSystemAudioModeStatus_off() {
    public void handleGiveSystemAudioModeStatus_off() {
        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
            .buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
            .buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);

        HdmiCecMessage messageGive = HdmiCecMessageBuilder
        HdmiCecMessage message = HdmiCecMessageBuilder
            .buildGiveSystemAudioModeStatus(ADDR_TV, ADDR_AUDIO_SYSTEM);
            .buildGiveSystemAudioModeStatus(ADDR_TV, ADDR_AUDIO_SYSTEM);
        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(message));


        assertTrue(mResultMessage.equals(expectMessage));
        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive));
        mTestLooper.dispatchAll();
        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
    }
    }


    @Test
    @Test
@@ -212,12 +233,12 @@ public class HdmiCecLocalDeviceAudioSystemTest {
        // TODO(b/80296911): Add tests when finishing handler impl.
        // TODO(b/80296911): Add tests when finishing handler impl.
        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
            .buildInitiateArc(ADDR_AUDIO_SYSTEM, ADDR_TV);
            .buildInitiateArc(ADDR_AUDIO_SYSTEM, ADDR_TV);

        HdmiCecMessage message = HdmiCecMessageBuilder
        HdmiCecMessage message = HdmiCecMessageBuilder
            .buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
            .buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message));


        assertTrue(mResultMessage.equals(expectMessage));
        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message));
        mTestLooper.dispatchAll();
        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
    }
    }


    @Test
    @Test
@@ -225,11 +246,81 @@ public class HdmiCecLocalDeviceAudioSystemTest {
        // TODO(b/80297105): Add tests when finishing handler impl.
        // TODO(b/80297105): Add tests when finishing handler impl.
        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
            .buildTerminateArc(ADDR_AUDIO_SYSTEM, ADDR_TV);
            .buildTerminateArc(ADDR_AUDIO_SYSTEM, ADDR_TV);

        HdmiCecMessage messageRequestOff = HdmiCecMessageBuilder
        HdmiCecMessage message = HdmiCecMessageBuilder
            .buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM);
            .buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM);
        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message));


        assertTrue(mResultMessage.equals(expectMessage));
        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(messageRequestOff));
        mTestLooper.dispatchAll();
        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
    }

    @Test
    public void handleSystemAudioModeRequest_turnOffByTv_originalOff() {
        HdmiCecMessage messageRequest = HdmiCecMessageBuilder
            .buildSystemAudioModeRequest(ADDR_TV, ADDR_AUDIO_SYSTEM, 2, false);
        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
            .buildSetSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false);

        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleSystemAudioModeRequest(messageRequest));
        mTestLooper.dispatchAll();
        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
    }

    @Test
    public void handleSetSystemAudioMode_setOn() {
        HdmiCecMessage messageSet = HdmiCecMessageBuilder
            .buildSetSystemAudioMode(ADDR_TV, ADDR_AUDIO_SYSTEM, true);
        HdmiCecMessage messageGive = HdmiCecMessageBuilder
            .buildGiveSystemAudioModeStatus(ADDR_TV, ADDR_AUDIO_SYSTEM);

        // Check if originally off
        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
            .buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);

        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive));
        mTestLooper.dispatchAll();
        assertEquals(expectMessage, mNativeWrapper.getResultMessage());

        // Check if correctly turned on
        expectMessage = HdmiCecMessageBuilder
            .buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, true);

        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleSetSystemAudioMode(messageSet));
        mTestLooper.dispatchAll();
        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive));
        mTestLooper.dispatchAll();
        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
    }

    @Test
    public void handleSystemAudioModeRequest_turnOnByTv_thenTurnOffByTv() {
        mMusicMute = true;
        HdmiCecMessage messageRequestOn = HdmiCecMessageBuilder
            .buildSystemAudioModeRequest(ADDR_TV, ADDR_AUDIO_SYSTEM, 2, true);
        HdmiCecMessage messageGive = HdmiCecMessageBuilder
            .buildGiveSystemAudioModeStatus(ADDR_TV, ADDR_AUDIO_SYSTEM);
        // Turn the feature on
        HdmiCecMessage expectMessage = HdmiCecMessageBuilder
            .buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, true);

        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleSystemAudioModeRequest(messageRequestOn));
        mTestLooper.dispatchAll();
        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive));
        mTestLooper.dispatchAll();
        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
        assertFalse(mMusicMute);

        // Check if feature correctly turned off
        HdmiCecMessage messageRequestOff = HdmiCecMessageBuilder
            .buildSystemAudioModeRequest(ADDR_TV, ADDR_AUDIO_SYSTEM, 2, false);
        expectMessage = HdmiCecMessageBuilder
            .buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);

        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleSystemAudioModeRequest(messageRequestOff));
        mTestLooper.dispatchAll();
        assertTrue(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive));
        mTestLooper.dispatchAll();
        assertEquals(expectMessage, mNativeWrapper.getResultMessage());
        assertTrue(mMusicMute);
    }
    }
}
}