Create and remove HdmiEarcLocalDeviceTx
Create when HdmiControlService is started, or eARC gets enabled. Remove when eARC gets disabled. Test: atest Bug: 240388108 Change-Id: I1c563de3022ab3b614b6b71fc36250daced9b06b
This commit is contained in:
@@ -18,6 +18,7 @@ package com.android.server.hdmi;
|
||||
|
||||
import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE;
|
||||
import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE;
|
||||
import static android.hardware.hdmi.HdmiControlManager.EARC_FEATURE_ENABLED;
|
||||
import static android.hardware.hdmi.HdmiControlManager.HDMI_CEC_CONTROL_ENABLED;
|
||||
import static android.hardware.hdmi.HdmiControlManager.SOUNDBAR_MODE_DISABLED;
|
||||
import static android.hardware.hdmi.HdmiControlManager.SOUNDBAR_MODE_ENABLED;
|
||||
@@ -184,13 +185,14 @@ public class HdmiControlService extends SystemService {
|
||||
|
||||
static final String PERMISSION = "android.permission.HDMI_CEC";
|
||||
|
||||
// The reason code to initiate initializeCec().
|
||||
// The reason code to initiate initializeCec() and initializeEarc().
|
||||
static final int INITIATED_BY_ENABLE_CEC = 0;
|
||||
static final int INITIATED_BY_BOOT_UP = 1;
|
||||
static final int INITIATED_BY_SCREEN_ON = 2;
|
||||
static final int INITIATED_BY_WAKE_UP_MESSAGE = 3;
|
||||
static final int INITIATED_BY_HOTPLUG = 4;
|
||||
static final int INITIATED_BY_SOUNDBAR_MODE = 5;
|
||||
static final int INITIATED_BY_ENABLE_EARC = 6;
|
||||
|
||||
// The reason code representing the intent action that drives the standby
|
||||
// procedure. The procedure starts either by Intent.ACTION_SCREEN_OFF or
|
||||
@@ -384,6 +386,15 @@ public class HdmiControlService extends SystemService {
|
||||
@HdmiControlManager.HdmiCecControl
|
||||
private int mHdmiControlEnabled;
|
||||
|
||||
// Set to true while the eARC feature is supported by the hardware and the eARC HAL is present.
|
||||
@GuardedBy("mLock")
|
||||
@VisibleForTesting
|
||||
protected boolean mEarcSupported;
|
||||
|
||||
// Set to true while the eARC feature is enabled.
|
||||
@GuardedBy("mLock")
|
||||
private boolean mEarcEnabled;
|
||||
|
||||
// Set to true while the service is in normal mode. While set to false, no input change is
|
||||
// allowed. Used for situations where input change can confuse users such as channel auto-scan,
|
||||
// system upgrade, etc., a.k.a. "prohibit mode".
|
||||
@@ -417,6 +428,9 @@ public class HdmiControlService extends SystemService {
|
||||
|
||||
private HdmiCecPowerStatusController mPowerStatusController;
|
||||
|
||||
@Nullable
|
||||
private HdmiEarcLocalDevice mEarcLocalDevice;
|
||||
|
||||
@ServiceThreadOnly
|
||||
private String mMenuLanguage = localeToMenuLanguage(Locale.getDefault());
|
||||
|
||||
@@ -631,9 +645,13 @@ public class HdmiControlService extends SystemService {
|
||||
mPowerStatusController = new HdmiCecPowerStatusController(this);
|
||||
}
|
||||
mPowerStatusController.setPowerStatus(getInitialPowerStatus());
|
||||
mProhibitMode = false;
|
||||
setProhibitMode(false);
|
||||
mHdmiControlEnabled = mHdmiCecConfig.getIntValue(
|
||||
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
|
||||
synchronized (mLock) {
|
||||
mEarcEnabled = (mHdmiCecConfig.getIntValue(
|
||||
HdmiControlManager.SETTING_NAME_EARC_ENABLED) == EARC_FEATURE_ENABLED);
|
||||
}
|
||||
setHdmiCecVolumeControlEnabledInternal(getHdmiCecConfig().getIntValue(
|
||||
HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE));
|
||||
mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true);
|
||||
@@ -655,11 +673,16 @@ public class HdmiControlService extends SystemService {
|
||||
Slog.i(TAG, "Device does not support MHL-control.");
|
||||
}
|
||||
mHdmiCecNetwork = new HdmiCecNetwork(this, mCecController, mMhlController);
|
||||
if (mHdmiControlEnabled == HdmiControlManager.HDMI_CEC_CONTROL_ENABLED) {
|
||||
if (isCecControlEnabled()) {
|
||||
initializeCec(INITIATED_BY_BOOT_UP);
|
||||
} else {
|
||||
mCecController.enableCec(false);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
if (mEarcSupported && mEarcEnabled) {
|
||||
initializeEarc(INITIATED_BY_BOOT_UP);
|
||||
}
|
||||
}
|
||||
mMhlDevices = Collections.emptyList();
|
||||
|
||||
mHdmiCecNetwork.initPortInfo();
|
||||
@@ -743,8 +766,16 @@ public class HdmiControlService extends SystemService {
|
||||
mCecController.enableWakeupByOtp(tv().getAutoWakeup());
|
||||
}
|
||||
}
|
||||
},
|
||||
mServiceThreadExecutor);
|
||||
}, mServiceThreadExecutor);
|
||||
mHdmiCecConfig.registerChangeListener(HdmiControlManager.SETTING_NAME_EARC_ENABLED,
|
||||
new HdmiCecConfig.SettingChangeListener() {
|
||||
@Override
|
||||
public void onChange(String setting) {
|
||||
@HdmiControlManager.HdmiCecControl int enabled = mHdmiCecConfig.getIntValue(
|
||||
HdmiControlManager.SETTING_NAME_EARC_ENABLED);
|
||||
setEarcEnabled(enabled);
|
||||
}
|
||||
}, mServiceThreadExecutor);
|
||||
}
|
||||
|
||||
/** Returns true if the device screen is off */
|
||||
@@ -1083,7 +1114,8 @@ public class HdmiControlService extends SystemService {
|
||||
}
|
||||
|
||||
@ServiceThreadOnly
|
||||
private void initializeCecLocalDevices(final int initiatedBy) {
|
||||
@VisibleForTesting
|
||||
protected void initializeCecLocalDevices(final int initiatedBy) {
|
||||
assertRunOnServiceThread();
|
||||
// A container for [Device type, Local device info].
|
||||
ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
|
||||
@@ -2568,7 +2600,9 @@ public class HdmiControlService extends SystemService {
|
||||
if (!DumpUtils.checkDumpPermission(getContext(), TAG, writer)) return;
|
||||
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
|
||||
|
||||
pw.println("mProhibitMode: " + mProhibitMode);
|
||||
synchronized (mLock) {
|
||||
pw.println("mProhibitMode: " + mProhibitMode);
|
||||
}
|
||||
pw.println("mPowerStatus: " + mPowerStatusController.getPowerStatus());
|
||||
pw.println("mIsCecAvailable: " + mIsCecAvailable);
|
||||
pw.println("mCecVersion: " + mCecVersion);
|
||||
@@ -2577,9 +2611,9 @@ public class HdmiControlService extends SystemService {
|
||||
// System settings
|
||||
pw.println("System_settings:");
|
||||
pw.increaseIndent();
|
||||
pw.println("mMhlInputChangeEnabled: " + mMhlInputChangeEnabled);
|
||||
pw.println("mMhlInputChangeEnabled: " + isMhlInputChangeEnabled());
|
||||
pw.println("mSystemAudioActivated: " + isSystemAudioActivated());
|
||||
pw.println("mHdmiCecVolumeControlEnabled: " + mHdmiCecVolumeControl);
|
||||
pw.println("mHdmiCecVolumeControlEnabled: " + getHdmiCecVolumeControl());
|
||||
pw.decreaseIndent();
|
||||
|
||||
// CEC settings
|
||||
@@ -2605,6 +2639,14 @@ public class HdmiControlService extends SystemService {
|
||||
pw.increaseIndent();
|
||||
mMhlController.dump(pw);
|
||||
pw.decreaseIndent();
|
||||
pw.print("eARC local device: ");
|
||||
pw.increaseIndent();
|
||||
if (mEarcLocalDevice == null) {
|
||||
pw.println("None. eARC is either disabled or not available.");
|
||||
} else {
|
||||
mEarcLocalDevice.dump(pw);
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
mHdmiCecNetwork.dump(pw);
|
||||
if (mCecController != null) {
|
||||
pw.println("mCecController: ");
|
||||
@@ -3313,6 +3355,12 @@ public class HdmiControlService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEarcSupportedAndEnabled() {
|
||||
synchronized (mLock) {
|
||||
return mEarcSupported && mEarcEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
@ServiceThreadOnly
|
||||
int getPowerStatus() {
|
||||
assertRunOnServiceThread();
|
||||
@@ -3384,7 +3432,7 @@ public class HdmiControlService extends SystemService {
|
||||
mPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON,
|
||||
false);
|
||||
if (mCecController != null) {
|
||||
if (mHdmiControlEnabled == HDMI_CEC_CONTROL_ENABLED) {
|
||||
if (isCecControlEnabled()) {
|
||||
int startReason = -1;
|
||||
switch (wakeUpAction) {
|
||||
case WAKE_UP_SCREEN_ON:
|
||||
@@ -3406,6 +3454,22 @@ 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;
|
||||
|
||||
}
|
||||
initializeEarc(startReason);
|
||||
}
|
||||
// TODO: Initialize MHL local devices.
|
||||
}
|
||||
|
||||
@@ -4296,4 +4360,85 @@ public class HdmiControlService extends SystemService {
|
||||
getAudioManager().setStreamVolume(AudioManager.STREAM_MUSIC,
|
||||
volume * mStreamMusicMaxVolume / AudioStatus.MAX_VOLUME, flags);
|
||||
}
|
||||
|
||||
private void initializeEarc(int initiatedBy) {
|
||||
Slog.i(TAG, "eARC initialized, reason = " + initiatedBy);
|
||||
initializeEarcLocalDevice(initiatedBy);
|
||||
}
|
||||
|
||||
@ServiceThreadOnly
|
||||
@VisibleForTesting
|
||||
protected void initializeEarcLocalDevice(final int initiatedBy) {
|
||||
// TODO remove initiatedBy argument if it stays unused
|
||||
assertRunOnServiceThread();
|
||||
if (isTvDevice() && mEarcLocalDevice == null) {
|
||||
mEarcLocalDevice = new HdmiEarcLocalDeviceTx();
|
||||
}
|
||||
// TODO create HdmiEarcLocalDeviceRx if we're an audio system device.
|
||||
}
|
||||
|
||||
@ServiceThreadOnly
|
||||
@VisibleForTesting
|
||||
protected void setEarcEnabled(@HdmiControlManager.EarcFeature int enabled) {
|
||||
assertRunOnServiceThread();
|
||||
synchronized (mLock) {
|
||||
mEarcEnabled = (enabled == EARC_FEATURE_ENABLED);
|
||||
|
||||
if (!mEarcSupported) {
|
||||
Slog.i(TAG, "Enabled/disabled eARC setting, but the hardware doesn´t support eARC."
|
||||
+ "This settings change doesn´t have an effect.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEarcEnabled) {
|
||||
onEnableEarc();
|
||||
return;
|
||||
}
|
||||
}
|
||||
runOnServiceThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onDisableEarc();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void setEarcSupported(boolean supported) {
|
||||
synchronized (mLock) {
|
||||
mEarcSupported = supported;
|
||||
}
|
||||
}
|
||||
|
||||
@ServiceThreadOnly
|
||||
private void onEnableEarc() {
|
||||
initializeEarc(INITIATED_BY_ENABLE_EARC);
|
||||
}
|
||||
|
||||
@ServiceThreadOnly
|
||||
private void onDisableEarc() {
|
||||
clearEarcLocalDevice();
|
||||
}
|
||||
|
||||
@ServiceThreadOnly
|
||||
@VisibleForTesting
|
||||
protected void clearEarcLocalDevice() {
|
||||
assertRunOnServiceThread();
|
||||
mEarcLocalDevice = null;
|
||||
}
|
||||
|
||||
@ServiceThreadOnly
|
||||
@VisibleForTesting
|
||||
protected void addEarcLocalDevice(HdmiEarcLocalDevice localDevice) {
|
||||
assertRunOnServiceThread();
|
||||
mEarcLocalDevice = localDevice;
|
||||
}
|
||||
|
||||
@ServiceThreadOnly
|
||||
@VisibleForTesting
|
||||
protected HdmiEarcLocalDevice getEarcLocalDevice() {
|
||||
assertRunOnServiceThread();
|
||||
return mEarcLocalDevice;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 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 {
|
||||
private static final String TAG = "HdmiEarcLocalDevice";
|
||||
|
||||
/** Dump internal status of HdmiEarcLocalDevice object */
|
||||
protected void dump(final IndentingPrintWriter pw) {
|
||||
// Should be overridden in the more specific classes
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 android.util.IndentingPrintWriter;
|
||||
|
||||
/**
|
||||
* Represents a local eARC device of type TX residing in the Android system.
|
||||
* Only TV panel devices can have a local eARC TX device.
|
||||
*/
|
||||
public class HdmiEarcLocalDeviceTx extends HdmiEarcLocalDevice {
|
||||
private static final String TAG = "HdmiEarcLocalDeviceTx";
|
||||
|
||||
/** Dump internal status of HdmiEarcLocalDeviceTx object */
|
||||
protected void dump(final IndentingPrintWriter pw) {
|
||||
pw.println("TX");
|
||||
}
|
||||
}
|
||||
@@ -605,4 +605,36 @@ public class HdmiCecNetworkTest {
|
||||
|
||||
assertThat(mHdmiCecNetwork.getSafeCecDevicesLocked()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disableCec_clearCecLocalDevices() {
|
||||
mHdmiCecNetwork.clearLocalDevices();
|
||||
mHdmiCecNetwork.addLocalDevice(HdmiDeviceInfo.DEVICE_TV,
|
||||
new HdmiCecLocalDeviceTv(mHdmiControlService));
|
||||
|
||||
assertThat(mHdmiCecNetwork.getLocalDeviceList()).hasSize(1);
|
||||
assertThat(mHdmiCecNetwork.getLocalDeviceList().get(0)).isInstanceOf(
|
||||
HdmiCecLocalDeviceTv.class);
|
||||
mHdmiControlService.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertThat(mHdmiCecNetwork.getLocalDeviceList()).hasSize(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disableEarc_doNotClearCecLocalDevices() {
|
||||
mHdmiCecNetwork.clearLocalDevices();
|
||||
mHdmiCecNetwork.addLocalDevice(HdmiDeviceInfo.DEVICE_TV,
|
||||
new HdmiCecLocalDeviceTv(mHdmiControlService));
|
||||
|
||||
assertThat(mHdmiCecNetwork.getLocalDeviceList()).hasSize(1);
|
||||
assertThat(mHdmiCecNetwork.getLocalDeviceList().get(0)).isInstanceOf(
|
||||
HdmiCecLocalDeviceTv.class);
|
||||
mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertThat(mHdmiCecNetwork.getLocalDeviceList()).hasSize(1);
|
||||
assertThat(mHdmiCecNetwork.getLocalDeviceList().get(0)).isInstanceOf(
|
||||
HdmiCecLocalDeviceTv.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
@@ -1082,6 +1083,54 @@ public class HdmiControlServiceTest {
|
||||
assertThat(mHdmiControlServiceSpy.audioSystem()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disableEarc_clearEarcLocalDevice() {
|
||||
mHdmiControlServiceSpy.setEarcSupported(true);
|
||||
mHdmiControlServiceSpy.clearEarcLocalDevice();
|
||||
mHdmiControlServiceSpy.addEarcLocalDevice(new HdmiEarcLocalDeviceTx());
|
||||
assertThat(mHdmiControlServiceSpy.getEarcLocalDevice()).isNotNull();
|
||||
|
||||
mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED);
|
||||
mTestLooper.dispatchAll();
|
||||
assertThat(mHdmiControlServiceSpy.getEarcLocalDevice()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disableCec_doNotClearEarcLocalDevice() {
|
||||
mHdmiControlServiceSpy.setEarcSupported(true);
|
||||
mHdmiControlServiceSpy.clearEarcLocalDevice();
|
||||
mHdmiControlServiceSpy.addEarcLocalDevice(new HdmiEarcLocalDeviceTx());
|
||||
assertThat(mHdmiControlServiceSpy.getEarcLocalDevice()).isNotNull();
|
||||
|
||||
mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
|
||||
mTestLooper.dispatchAll();
|
||||
assertThat(mHdmiControlServiceSpy.getEarcLocalDevice()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableCec_initializeCecLocalDevices() {
|
||||
mHdmiControlServiceSpy.setEarcSupported(true);
|
||||
Mockito.clearInvocations(mHdmiControlServiceSpy);
|
||||
mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
|
||||
mTestLooper.dispatchAll();
|
||||
mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
|
||||
mTestLooper.dispatchAll();
|
||||
verify(mHdmiControlServiceSpy, times(1)).initializeCecLocalDevices(anyInt());
|
||||
verify(mHdmiControlServiceSpy, times(0)).initializeEarcLocalDevice(anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableEarc_initializeEarcLocalDevices() {
|
||||
mHdmiControlServiceSpy.setEarcSupported(true);
|
||||
Mockito.clearInvocations(mHdmiControlServiceSpy);
|
||||
mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED);
|
||||
mTestLooper.dispatchAll();
|
||||
mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
|
||||
mTestLooper.dispatchAll();
|
||||
verify(mHdmiControlServiceSpy, times(0)).initializeCecLocalDevices(anyInt());
|
||||
verify(mHdmiControlServiceSpy, times(1)).initializeEarcLocalDevice(anyInt());
|
||||
}
|
||||
|
||||
protected static class MockPlaybackDevice extends HdmiCecLocalDevicePlayback {
|
||||
|
||||
private boolean mCanGoToStandby;
|
||||
|
||||
Reference in New Issue
Block a user