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

Commit ab8211ad authored by Paul Colta's avatar Paul Colta Committed by Android (Google) Code Review
Browse files

Merge "HDMI: Disable CEC on standby when Low Power Standby is enabled" into main

parents 87e02002 5c3a99a0
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -509,6 +509,21 @@ final class Constants {
    static final String PROPERTY_STRIP_AUDIO_TV_NO_SYSTEM_AUDIO =
        "persist.sys.hdmi.property_strip_audio_tv_no_system_audio";

    /**
     * Property that decides whether CEC should be disabled on standby when the low energy mode
     * option is used.
     */
    static final String PROPERTY_WAS_CEC_DISABLED_ON_STANDBY_BY_LOW_ENERGY_MODE =
            "persist.sys.hdmi.property_was_cec_disabled_on_standby_by_low_energy_mode";

    /**
     * Property that checks if CEC was disabled on standby by low energy mode. With the help of this
     * property we avoid re-enabling CEC if the user explicitly disabled it, unrelated to the
     * selected energy mode.
     */
    static final String PROPERTY_DISABLE_CEC_ON_STANDBY_IN_LOW_ENERGY_MODE =
            "persist.sys.hdmi.property_disable_cec_on_standby_in_low_energy_mode";

    static final int RECORDING_TYPE_DIGITAL_RF = 1;
    static final int RECORDING_TYPE_ANALOGUE_RF = 2;
    static final int RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 3;
@@ -644,6 +659,11 @@ final class Constants {
    })
    @interface FeatureFlag {}

    /**
     * Identifier key for Low energy mode.
     */
    static final String KEY_LOW_ENERGY_USE = "low_energy_use";

    private Constants() {
        /* cannot be instantiated */
    }
+67 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ 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_DISABLED;
import static android.hardware.hdmi.HdmiControlManager.EARC_FEATURE_ENABLED;
import static android.hardware.hdmi.HdmiControlManager.HDMI_CEC_CONTROL_DISABLED;
import static android.hardware.hdmi.HdmiControlManager.HDMI_CEC_CONTROL_ENABLED;
import static android.hardware.hdmi.HdmiControlManager.POWER_CONTROL_MODE_NONE;
import static android.hardware.hdmi.HdmiControlManager.SOUNDBAR_MODE_DISABLED;
@@ -478,7 +479,8 @@ public class HdmiControlService extends SystemService {
    @Nullable
    private HdmiCecController mCecController;

    private HdmiCecPowerStatusController mPowerStatusController;
    @VisibleForTesting
    protected HdmiCecPowerStatusController mPowerStatusController;

    @Nullable
    private HdmiEarcController mEarcController;
@@ -3814,7 +3816,32 @@ public class HdmiControlService extends SystemService {
        mPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON,
                false);
        if (mCecController != null) {
            if (isCecControlEnabled()) {
            if (isTvDevice() && getWasCecDisabledOnStandbyByLowEnergyMode()) {
                Slog.w(TAG, "Re-enable CEC on wake-up since it was disabled due to low energy "
                        + " mode.");
                getHdmiCecConfig().setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
                        HDMI_CEC_CONTROL_ENABLED);
                setWasCecDisabledOnStandbyByLowEnergyMode(false);
                int controlStateChangedReason = -1;
                switch (wakeUpAction) {
                    case WAKE_UP_SCREEN_ON:
                        controlStateChangedReason =
                                HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP;
                        break;
                    case WAKE_UP_BOOT_UP:
                        controlStateChangedReason =
                                HdmiControlManager.CONTROL_STATE_CHANGED_REASON_START;
                        break;
                    default:
                        Slog.e(TAG, "wakeUpAction " + wakeUpAction + " not defined.");
                        return;

                }
                // Since CEC is going to be initialized by the setting value update, we must invoke
                // the vendor command listeners here with the reason TV woke up.
                invokeVendorCommandListenersOnControlStateChanged(true,
                        controlStateChangedReason);
            } else if (isCecControlEnabled()) {
                int startReason = -1;
                switch (wakeUpAction) {
                    case WAKE_UP_SCREEN_ON:
@@ -3988,6 +4015,14 @@ public class HdmiControlService extends SystemService {
                if (isAudioSystemDevice() || !isPowerStandby()) {
                    return;
                }
                if (isTvDevice() && getDisableCecOnStandbyByLowEnergyMode()
                        && mPowerManager.isLowPowerStandbyEnabled()) {
                    Slog.w(TAG, "Disable CEC on standby due to low power energy mode.");
                    setWasCecDisabledOnStandbyByLowEnergyMode(true);
                    getHdmiCecConfig().setIntValue(
                            HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
                            HDMI_CEC_CONTROL_DISABLED);
                }
                mCecController.enableSystemCecControl(false);
                mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, DISABLED);
            }
@@ -5148,4 +5183,34 @@ public class HdmiControlService extends SystemService {
    protected boolean isHdmiControlEnhancedBehaviorFlagEnabled() {
        return hdmiControlEnhancedBehavior();
    }

    /**
     * Reads the property value that decides whether CEC should be disabled on standby when the low
     * energy mode option is used.
     */
    @VisibleForTesting
    protected boolean getDisableCecOnStandbyByLowEnergyMode() {
        return SystemProperties.getBoolean(
                Constants.PROPERTY_DISABLE_CEC_ON_STANDBY_IN_LOW_ENERGY_MODE, false);
    }

    /**
     * Reads the property that checks if CEC was disabled on standby by low energy mode.
     */
    @VisibleForTesting
    protected boolean getWasCecDisabledOnStandbyByLowEnergyMode() {
        return SystemProperties.getBoolean(
                Constants.PROPERTY_WAS_CEC_DISABLED_ON_STANDBY_BY_LOW_ENERGY_MODE, false);
    }

    /**
     * Sets the truth value of the property that checks if CEC was disabled on standby by low energy
     * mode.
     */
    @VisibleForTesting
    protected void setWasCecDisabledOnStandbyByLowEnergyMode(boolean value) {
        writeStringSystemProperty(
                Constants.PROPERTY_WAS_CEC_DISABLED_ON_STANDBY_BY_LOW_ENERGY_MODE,
                String.valueOf(value));
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.hdmi;

import static com.android.server.hdmi.Constants.KEY_LOW_ENERGY_USE;

import android.content.Context;
import android.os.PowerManager;

@@ -47,6 +49,12 @@ public class PowerManagerWrapper {
        return new DefaultWakeLockWrapper(mPowerManager.newWakeLock(levelAndFlags, tag));
    }

    boolean isLowPowerStandbyEnabled() {
        PowerManager.LowPowerStandbyPolicy lowPowerStandbyPolicy
                = mPowerManager.getLowPowerStandbyPolicy();
        return lowPowerStandbyPolicy.getIdentifier().equals(KEY_LOW_ENERGY_USE);
    }

    /**
     * "Default" wrapper for {@link PowerManager.WakeLock}, as opposed to a "Fake" wrapper for
     * testing - see {@link FakePowerManagerWrapper.FakeWakeLockWrapper}.
+10 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ final class FakePowerManagerWrapper extends PowerManagerWrapper {
    private boolean mInteractive;
    private WakeLockWrapper mWakeLock;
    private boolean mWasWakeLockInstanceCreated = false;
    private boolean mIsLowPowerStandbyEnabled = false;


    FakePowerManagerWrapper(@NonNull Context context) {
@@ -59,6 +60,15 @@ final class FakePowerManagerWrapper extends PowerManagerWrapper {
        return;
    }

    @Override
    boolean isLowPowerStandbyEnabled() {
        return mIsLowPowerStandbyEnabled;
    }

    void setIsLowPowerStandbyEnabled(boolean isLowPowerStandbyEnabled) {
        mIsLowPowerStandbyEnabled = isLowPowerStandbyEnabled;
    }

    @Override
    WakeLockWrapper newWakeLock(int levelAndFlags, String tag) {
        if (mWakeLock == null) {
+143 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import org.junit.runners.JUnit4;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@SmallTest
@@ -113,6 +114,10 @@ public class HdmiCecLocalDeviceTvTest {
    private boolean mWokenUp;
    private boolean mEarcBlocksArc;
    private List<DeviceEventListener> mDeviceEventListeners = new ArrayList<>();
    private List<VendorCommandListener> mVendorCommandListeners = new ArrayList<>();
    private boolean mDisableCecOnStandbyByLowEnergyMode;
    private boolean mWasCecDisabledOnStandbyByLowEnergyMode;
    private boolean mUseHdmiCecPowerStatusController;

    private class DeviceEventListener {
        private HdmiDeviceInfo mDevice;
@@ -132,6 +137,30 @@ public class HdmiCecLocalDeviceTvTest {
        }
    }

    private class VendorCommandListener {
        private boolean mEnabled;
        private int mReason;

        VendorCommandListener(boolean enabled, int reason) {
            this.mEnabled = enabled;
            this.mReason = reason;
        }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof VendorCommandListener)) {
                return false;
            }
            VendorCommandListener other = (VendorCommandListener) obj;
            return other.mReason == mReason && other.mEnabled == mEnabled;
        }

        @Override
        public int hashCode() {
            return Objects.hash(mEnabled, mReason);
        }
    }

    private FakeAudioFramework mAudioFramework;
    private AudioManagerWrapper mAudioManager;

@@ -169,6 +198,9 @@ public class HdmiCecLocalDeviceTvTest {

                    @Override
                    boolean isPowerStandby() {
                        if (mUseHdmiCecPowerStatusController) {
                            return mPowerStatusController.isPowerStatusStandby();
                        }
                        return false;
                    }

@@ -187,6 +219,13 @@ public class HdmiCecLocalDeviceTvTest {
                        mDeviceEventListeners.add(new DeviceEventListener(device, status));
                    }

                    @Override
                    boolean invokeVendorCommandListenersOnControlStateChanged(
                            boolean enabled, int reason) {
                        mVendorCommandListeners.add(new VendorCommandListener(enabled, reason));
                        return true;
                    }

                    @Override
                    protected boolean earcBlocksArcConnection() {
                        return mEarcBlocksArc;
@@ -196,6 +235,21 @@ public class HdmiCecLocalDeviceTvTest {
                    protected void sendBroadcastAsUser(@RequiresPermission Intent intent) {
                        // do nothing
                    }

                    @Override
                    protected boolean getDisableCecOnStandbyByLowEnergyMode() {
                        return mDisableCecOnStandbyByLowEnergyMode;
                    }

                    @Override
                    protected boolean getWasCecDisabledOnStandbyByLowEnergyMode() {
                        return mWasCecDisabledOnStandbyByLowEnergyMode;
                    }

                    @Override
                    protected void setWasCecDisabledOnStandbyByLowEnergyMode(boolean value) {
                        mWasCecDisabledOnStandbyByLowEnergyMode = value;
                    }
                };

        mHdmiControlService.setIoLooper(mMyLooper);
@@ -241,6 +295,9 @@ public class HdmiCecLocalDeviceTvTest {
            mHdmiControlService.getHdmiCecConfig().setIntValue(
                    sad, HdmiControlManager.QUERY_SAD_DISABLED);
        }
        mWasCecDisabledOnStandbyByLowEnergyMode = false;
        mDisableCecOnStandbyByLowEnergyMode = false;
        mUseHdmiCecPowerStatusController = false;
        mNativeWrapper.clearResultMessages();
    }

@@ -2238,6 +2295,92 @@ public class HdmiCecLocalDeviceTvTest {
        assertThat(mHdmiCecLocalDeviceTv.getActions(SystemAudioActionFromTv.class)).hasSize(1);
    }

    @Test
    public void lowEnergyMode_disableCecOnStandby_reEnableOnWakeup() {
        mDisableCecOnStandbyByLowEnergyMode = true;
        mUseHdmiCecPowerStatusController = true;
        mPowerManager.setIsLowPowerStandbyEnabled(true);

        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
        mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
        mTestLooper.dispatchAll();

        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
                HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
        assertTrue(mWasCecDisabledOnStandbyByLowEnergyMode);
        mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
        mTestLooper.dispatchAll();

        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
        assertFalse(mWasCecDisabledOnStandbyByLowEnergyMode);
    }

    @Test
    public void lowEnergyMode_disableCecBeforeStandby_cecStaysDisabledOnWakeup() {
        mDisableCecOnStandbyByLowEnergyMode = true;
        mUseHdmiCecPowerStatusController = true;
        mPowerManager.setIsLowPowerStandbyEnabled(true);

        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
        mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
                HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
        mTestLooper.dispatchAll();

        mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
        mTestLooper.dispatchAll();

        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
                HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
        assertFalse(mWasCecDisabledOnStandbyByLowEnergyMode);
        mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
        mTestLooper.dispatchAll();

        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
                HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
    }

    @Test
    public void lowEnergyMode_onWakeUp_reEnableCec_invokeVendorCommandListeners() {
        mDisableCecOnStandbyByLowEnergyMode = true;
        mUseHdmiCecPowerStatusController = true;
        mPowerManager.setIsLowPowerStandbyEnabled(true);
        VendorCommandListener vendorCommandListenerInvocationWakeup = new VendorCommandListener(
                true, HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP);
        VendorCommandListener vendorCommandListenerInvocationSettingChange =
                new VendorCommandListener(true,
                        HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP);

        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
        mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
        mTestLooper.dispatchAll();

        assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
                        HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
                HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
        assertTrue(mWasCecDisabledOnStandbyByLowEnergyMode);
        mVendorCommandListeners.clear();
        mTestLooper.dispatchAll();

        mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
        mTestLooper.dispatchAll();

        assertThat(mVendorCommandListeners.size()).isEqualTo(2);
        assertTrue(mVendorCommandListeners.contains(vendorCommandListenerInvocationWakeup));
        assertTrue(mVendorCommandListeners.contains(vendorCommandListenerInvocationSettingChange));
    }

    protected static class MockTvDevice extends HdmiCecLocalDeviceTv {
        MockTvDevice(HdmiControlService service) {
            super(service);