diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index b4d7fb9d91532..689183fbbf74a 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -54,7 +54,7 @@ import java.util.concurrent.ArrayBlockingQueue; * Class that models a logical CEC device hosted in this system. Handles initialization, CEC * commands that call for actions customized per device type. */ -abstract class HdmiCecLocalDevice { +abstract class HdmiCecLocalDevice extends HdmiLocalDevice { private static final String TAG = "HdmiCecLocalDevice"; private static final int MAX_HDMI_ACTIVE_SOURCE_HISTORY = 10; diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 7f5a7c8b7aae3..45c7de9763b7a 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -713,8 +713,12 @@ public class HdmiControlService extends SystemService { mEarcSupported &= (mEarcController != null); } - if (isEarcSupportedAndEnabled()) { - initializeEarc(INITIATED_BY_BOOT_UP); + if (isEarcSupported()) { + if (isEarcEnabled()) { + initializeEarc(INITIATED_BY_BOOT_UP); + } else { + setEarcEnabledInHal(false); + } } mHdmiCecConfig.registerChangeListener(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, @@ -3386,9 +3390,15 @@ public class HdmiControlService extends SystemService { } } - private boolean isEarcSupportedAndEnabled() { + private boolean isEarcEnabled() { synchronized (mLock) { - return mEarcSupported && mEarcEnabled; + return mEarcEnabled; + } + } + + private boolean isEarcSupported() { + synchronized (mLock) { + return mEarcSupported; } } @@ -3485,21 +3495,24 @@ public class HdmiControlService extends SystemService { } else { Slog.i(TAG, "Device does not support HDMI-CEC."); } - if (isEarcSupportedAndEnabled()) { - int startReason = -1; - switch (wakeUpAction) { - case WAKE_UP_SCREEN_ON: - startReason = INITIATED_BY_SCREEN_ON; - break; - case WAKE_UP_BOOT_UP: - startReason = INITIATED_BY_BOOT_UP; - break; - default: - Slog.e(TAG, "wakeUpAction " + wakeUpAction + " not defined."); - return; - + if (isEarcSupported()) { + if (isEarcEnabled()) { + int startReason = -1; + switch (wakeUpAction) { + case WAKE_UP_SCREEN_ON: + startReason = INITIATED_BY_SCREEN_ON; + break; + case WAKE_UP_BOOT_UP: + startReason = INITIATED_BY_BOOT_UP; + break; + default: + Slog.e(TAG, "wakeUpAction " + wakeUpAction + " not defined."); + return; + } + initializeEarc(startReason); + } else { + setEarcEnabledInHal(false); } - initializeEarc(startReason); } // TODO: Initialize MHL local devices. } @@ -4394,6 +4407,7 @@ public class HdmiControlService extends SystemService { private void initializeEarc(int initiatedBy) { Slog.i(TAG, "eARC initialized, reason = " + initiatedBy); + setEarcEnabledInHal(true); initializeEarcLocalDevice(initiatedBy); } @@ -4415,8 +4429,8 @@ public class HdmiControlService extends SystemService { synchronized (mLock) { mEarcEnabled = (enabled == EARC_FEATURE_ENABLED); - if (!mEarcSupported) { - Slog.i(TAG, "Enabled/disabled eARC setting, but the hardware doesn´t support eARC." + if (!isEarcSupported()) { + Slog.i(TAG, "Enabled/disabled eARC setting, but the hardware doesn´t support eARC. " + "This settings change doesn´t have an effect."); return; } @@ -4448,6 +4462,8 @@ public class HdmiControlService extends SystemService { @ServiceThreadOnly private void onDisableEarc() { + disableEarcLocalDevice(); + setEarcEnabledInHal(false); clearEarcLocalDevice(); } @@ -4471,5 +4487,17 @@ public class HdmiControlService extends SystemService { assertRunOnServiceThread(); return mEarcLocalDevice; } + private void disableEarcLocalDevice() { + if (mEarcLocalDevice == null) { + return; + } + mEarcLocalDevice.disableDevice(); + } + @ServiceThreadOnly + @VisibleForTesting + protected void setEarcEnabledInHal(boolean enabled) { + assertRunOnServiceThread(); + mEarcController.setEarcEnabled(enabled); + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDevice.java index 1e9d338fc2d68..720dff5e77adb 100644 --- a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDevice.java @@ -22,9 +22,12 @@ import android.util.IndentingPrintWriter; * Class that models a local eARC device hosted in this system. * The class contains methods that are common between eARC TX and eARC RX devices. */ -public class HdmiEarcLocalDevice { +public class HdmiEarcLocalDevice extends HdmiLocalDevice { private static final String TAG = "HdmiEarcLocalDevice"; + protected void disableDevice() { + } + /** Dump internal status of HdmiEarcLocalDevice object */ protected void dump(final IndentingPrintWriter pw) { // Should be overridden in the more specific classes diff --git a/services/core/java/com/android/server/hdmi/HdmiLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiLocalDevice.java new file mode 100644 index 0000000000000..96fb28c5321ca --- /dev/null +++ b/services/core/java/com/android/server/hdmi/HdmiLocalDevice.java @@ -0,0 +1,26 @@ +/* + * 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; + +/** + * Class that models an HDMI device hosted in this system. + * Can be used to share methods between CEC and eARC local devices. + * Currently just a placeholder. + */ +abstract class HdmiLocalDevice { + private static final String TAG = "HdmiLocalDevice"; +} diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java index f07ee6c2be4e7..ff873faf02b7d 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -22,6 +22,7 @@ import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV; import static com.android.server.SystemService.PHASE_BOOT_COMPLETED; import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY; import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; +import static com.android.server.hdmi.HdmiControlService.WAKE_UP_SCREEN_ON; import static com.google.common.truth.Truth.assertThat; @@ -29,6 +30,7 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static junit.framework.TestCase.assertEquals; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doNothing; @@ -128,13 +130,13 @@ public class HdmiControlServiceTest { mLocalDevices.add(mPlaybackDeviceSpy); mHdmiPortInfo = new HdmiPortInfo[4]; mHdmiPortInfo[0] = - new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false); + new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false, false); mHdmiPortInfo[1] = - new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2200, true, false, false); + new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2200, true, false, false, false); mHdmiPortInfo[2] = - new HdmiPortInfo(3, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, false); + new HdmiPortInfo(3, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, true, true); mHdmiPortInfo[3] = - new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false); + new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false, false); mNativeWrapper.setPortInfo(mHdmiPortInfo); mHdmiControlServiceSpy.initService(); mPowerManager = new FakePowerManagerWrapper(mContextSpy); @@ -1131,6 +1133,124 @@ public class HdmiControlServiceTest { verify(mHdmiControlServiceSpy, times(1)).initializeEarcLocalDevice(anyInt()); } + @Test + public void disableCec_DoNotInformHalAboutEarc() { + mHdmiControlServiceSpy.setEarcSupported(true); + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(anyBoolean()); + } + + @Test + public void disableEarc_informHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_ENABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_DISABLED); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(true); + } + + @Test + public void enableCec_DoNotInformHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(anyBoolean()); + } + + @Test + public void enableEarc_informHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_DISABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_ENABLED); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(false); + } + + @Test + public void bootWithEarcEnabled_informHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_ENABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.initService(); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(false); + } + + @Test + public void bootWithEarcDisabled_informHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_DISABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.initService(); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(true); + } + + @Test + public void wakeUpWithEarcEnabled_informHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_ENABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(false); + } + + @Test + public void wakeUpWithEarcDisabled_informHalAboutEarc() { + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.SETTING_NAME_EARC_ENABLED, + HdmiControlManager.EARC_FEATURE_DISABLED); + mHdmiControlServiceSpy.setEarcSupported(true); + mTestLooper.dispatchAll(); + Mockito.clearInvocations(mHdmiControlServiceSpy); + mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON); + mTestLooper.dispatchAll(); + verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false); + verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(true); + } + protected static class MockPlaybackDevice extends HdmiCecLocalDevicePlayback { private boolean mCanGoToStandby;