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

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

Merge "HDMI: Improve implementation of PowerStatusMonitorActionFromPlayback" into main

parents 9bba6fab 5bc7e19f
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

/**
 * Represent a logical device of type Playback residing in Android system.
@@ -171,7 +172,11 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
                        }

                        if (mService.isHdmiControlEnhancedBehaviorFlagEnabled()) {
                            if (!hasAction(PowerStatusMonitorActionFromPlayback.class)) {
                            if (mService.getHdmiCecConfig().getStringValue(
                                    HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST)
                                    .equals(HdmiControlManager
                                            .POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW)
                                    && !hasAction(PowerStatusMonitorActionFromPlayback.class)) {
                                addAndStartAction(
                                        new PowerStatusMonitorActionFromPlayback(
                                                HdmiCecLocalDevicePlayback.this));
+23 −4
Original line number Diff line number Diff line
@@ -34,12 +34,17 @@ public class PowerStatusMonitorActionFromPlayback extends HdmiCecFeatureAction {
    // State that waits for <Report Power Status> once sending <Give Device Power Status>
    // to the TV.
    private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 2;
    // Number of consecutive standby reports required before going to standby.
    private static final int REQUIRED_CONSECUTIVE_STANDBY_REPORTS = 2;

    // Monitoring interval (60s)
    @VisibleForTesting
    protected static final int MONITORING_INTERVAL_MS = 60000;
    // Timeout once sending <Give Device Power Status>

    // Counter for consecutive standby reports
    private int mConsecutiveStandbyReports = 0;

    PowerStatusMonitorActionFromPlayback(HdmiCecLocalDevice source) {
        super(source);
    }
@@ -49,6 +54,7 @@ public class PowerStatusMonitorActionFromPlayback extends HdmiCecFeatureAction {
        // Start after timeout since the device just finished allocation.
        mState = STATE_WAIT_FOR_NEXT_MONITORING;
        addTimer(mState, MONITORING_INTERVAL_MS);
        mConsecutiveStandbyReports = 0;
        return true;
    }

@@ -64,13 +70,21 @@ public class PowerStatusMonitorActionFromPlayback extends HdmiCecFeatureAction {

    private boolean handleReportPowerStatusFromTv(HdmiCecMessage cmd) {
        int powerStatus = cmd.getParams()[0] & 0xFF;
        if (powerStatus == POWER_STATUS_STANDBY) {
            Slog.d(TAG, "TV reported it turned off, going to sleep.");
        if (powerStatus != POWER_STATUS_STANDBY) {
            mConsecutiveStandbyReports = 0; // Reset counter if TV is not in standby.
        } else {
            mConsecutiveStandbyReports++;  // Increase counter if TV reports standby.
        }

        if (mConsecutiveStandbyReports >= REQUIRED_CONSECUTIVE_STANDBY_REPORTS) {
            Slog.d(TAG, "TV reported standby, going to sleep.");
            source().getService().standby();
            finish();
            return true;
        }
        return false;
        // Schedule next monitoring.
        mState = STATE_WAIT_FOR_NEXT_MONITORING;
        addTimer(mState, MONITORING_INTERVAL_MS);
        return true;
    }

    @Override
@@ -84,6 +98,11 @@ public class PowerStatusMonitorActionFromPlayback extends HdmiCecFeatureAction {
                queryPowerStatus();
                break;
            case STATE_WAIT_FOR_REPORT_POWER_STATUS:
                // Timer expired while waiting for <Report Power Status>.
                // This means we didn't receive a power status report from the TV in time.
                Slog.d(TAG, "Timeout waiting for <Report Power Status>."
                        + " Resetting standby counter.");
                mConsecutiveStandbyReports = 0; // Reset counter on timeout
                mState = STATE_WAIT_FOR_NEXT_MONITORING;
                addTimer(mState, MONITORING_INTERVAL_MS);
                break;
+136 −5
Original line number Diff line number Diff line
@@ -2903,14 +2903,18 @@ public class HdmiCecLocalDevicePlaybackTest {
    }

    @Test
    public void powerStatusMonitorActionFromPlayback_TvReportPowerOff_goToSleep() {
    public void powerStatusMonitorActionFromPlayback_TvReportsStandbyTwice_goesToSleep() {
        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
                HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
                HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
        mTestLooper.dispatchAll();

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

        assertThat(mHdmiCecLocalDevicePlayback.getActions(
                PowerStatusMonitorActionFromPlayback.class)).hasSize(1);
        assertThat(mPowerManager.isInteractive()).isTrue();
        mNativeWrapper.clearResultMessages();
        mTestLooper.moveTimeForward(MONITORING_INTERVAL_MS);
        mTestLooper.dispatchAll();

@@ -2924,23 +2928,150 @@ public class HdmiCecLocalDevicePlaybackTest {
                HdmiCecMessageBuilder.buildReportPowerStatus(ADDR_TV, mPlaybackLogicalAddress,
                        HdmiControlManager.POWER_STATUS_STANDBY);

        assertThat(mNativeWrapper.getResultMessages().contains(givePowerStatus)).isTrue();
        assertThat(mNativeWrapper.getResultMessages()).contains(givePowerStatus);
        mNativeWrapper.clearResultMessages();
        // TV reports Standby (1st time)
        mNativeWrapper.onCecMessage(reportPowerStatusTvStandby);
        mTestLooper.dispatchAll();
        assertThat(mPowerManager.isInteractive()).isTrue(); // Should not go to sleep yet.
        mTestLooper.moveTimeForward(MONITORING_INTERVAL_MS);
        mTestLooper.dispatchAll();

        assertThat(mNativeWrapper.getResultMessages()).contains(givePowerStatus);
        mNativeWrapper.clearResultMessages();
        // TV reports Standby (2nd time)
        mNativeWrapper.onCecMessage(reportPowerStatusTvStandby);
        mTestLooper.dispatchAll();

        // Playback device should go to sleep
        assertThat(mPowerManager.isInteractive()).isFalse();
        assertThat(mHdmiCecLocalDevicePlayback.getActions(
                PowerStatusMonitorActionFromPlayback.class)).isEmpty();
    }

    @Test
    public void powerStatusMonitorActionFromPlayback_StandbyThenOnThenStandbyTwice_goesToSleep() {
        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
                HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
                HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
        mTestLooper.dispatchAll();

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

        assertThat(mHdmiCecLocalDevicePlayback.getActions(
                PowerStatusMonitorActionFromPlayback.class)).hasSize(1);
        assertThat(mPowerManager.isInteractive()).isTrue();

        HdmiCecMessage givePowerStatus =
                HdmiCecMessageBuilder.buildGiveDevicePowerStatus(mPlaybackLogicalAddress,
                        Constants.ADDR_TV);
        HdmiCecMessage reportPowerStatusTvStandby =
                HdmiCecMessageBuilder.buildReportPowerStatus(ADDR_TV, mPlaybackLogicalAddress,
                        HdmiControlManager.POWER_STATUS_STANDBY);
        HdmiCecMessage reportPowerStatusTvOn =
                HdmiCecMessageBuilder.buildReportPowerStatus(ADDR_TV, mPlaybackLogicalAddress,
                        HdmiControlManager.POWER_STATUS_ON);

        // First monitoring cycle: TV reports Standby (1st time)
        mTestLooper.moveTimeForward(MONITORING_INTERVAL_MS);
        mTestLooper.dispatchAll();
        assertThat(mNativeWrapper.getResultMessages()).contains(givePowerStatus);
        mNativeWrapper.clearResultMessages();
        mNativeWrapper.onCecMessage(reportPowerStatusTvStandby);
        mTestLooper.dispatchAll();
        assertThat(mPowerManager.isInteractive()).isTrue();

        // Second monitoring cycle: TV reports On (resets counter)
        mTestLooper.moveTimeForward(MONITORING_INTERVAL_MS);
        mTestLooper.dispatchAll();
        assertThat(mNativeWrapper.getResultMessages()).contains(givePowerStatus);
        mNativeWrapper.clearResultMessages();
        mNativeWrapper.onCecMessage(reportPowerStatusTvOn);
        mTestLooper.dispatchAll();
        assertThat(mPowerManager.isInteractive()).isTrue();

        // Third monitoring cycle: TV reports Standby (1st consecutive)
        mTestLooper.moveTimeForward(MONITORING_INTERVAL_MS);
        mTestLooper.dispatchAll();
        assertThat(mNativeWrapper.getResultMessages()).contains(givePowerStatus);
        mNativeWrapper.clearResultMessages();
        mNativeWrapper.onCecMessage(reportPowerStatusTvStandby);
        mTestLooper.dispatchAll();
        assertThat(mPowerManager.isInteractive()).isTrue();

        // Fourth monitoring cycle: TV reports Standby (2nd consecutive)
        mTestLooper.moveTimeForward(MONITORING_INTERVAL_MS);
        mTestLooper.dispatchAll();
        assertThat(mNativeWrapper.getResultMessages()).contains(givePowerStatus);
        mNativeWrapper.clearResultMessages();
        mNativeWrapper.onCecMessage(reportPowerStatusTvStandby);
        mTestLooper.dispatchAll();

        assertThat(mPowerManager.isInteractive()).isFalse();
        assertThat(mHdmiCecLocalDevicePlayback.getActions(
                PowerStatusMonitorActionFromPlayback.class)).isEmpty();
    }

    @Test
    public void powerStatusMonitorActionFromPlayback_StandbyTimeoutStandbyTwice_goesToSleep() {
        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
                HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
                HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
        mTestLooper.dispatchAll();

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

        assertThat(mHdmiCecLocalDevicePlayback.getActions(
                PowerStatusMonitorActionFromPlayback.class)).hasSize(1);
        assertThat(mPowerManager.isInteractive()).isTrue();

        HdmiCecMessage givePowerStatus =
                HdmiCecMessageBuilder.buildGiveDevicePowerStatus(mPlaybackLogicalAddress,
                        Constants.ADDR_TV);
        HdmiCecMessage reportPowerStatusTvStandby =
                HdmiCecMessageBuilder.buildReportPowerStatus(ADDR_TV, mPlaybackLogicalAddress,
                        HdmiControlManager.POWER_STATUS_STANDBY);

        // First monitoring cycle: TV reports Standby (1st time)
        mTestLooper.moveTimeForward(MONITORING_INTERVAL_MS);
        mTestLooper.dispatchAll();
        assertThat(mNativeWrapper.getResultMessages()).contains(givePowerStatus);
        mNativeWrapper.clearResultMessages();
        mNativeWrapper.onCecMessage(reportPowerStatusTvStandby);
        mTestLooper.dispatchAll();
        assertThat(mPowerManager.isInteractive()).isTrue();

        // Second monitoring cycle: Timeout waiting for report (resets counter)
        mTestLooper.moveTimeForward(MONITORING_INTERVAL_MS); // Triggers <Give Power Status>
        mTestLooper.dispatchAll();
        assertThat(mNativeWrapper.getResultMessages()).contains(givePowerStatus);
        mNativeWrapper.clearResultMessages();
        mTestLooper.moveTimeForward(TIMEOUT_MS);
        mTestLooper.moveTimeForward(TIMEOUT_MS); // Timeout for <Report Power Status>
        mTestLooper.dispatchAll();
        assertThat(mPowerManager.isInteractive()).isTrue();

        // Third monitoring cycle: TV reports Standby (1st consecutive)
        mTestLooper.moveTimeForward(MONITORING_INTERVAL_MS);
        mTestLooper.dispatchAll();
        assertThat(mNativeWrapper.getResultMessages()).contains(givePowerStatus);
        mNativeWrapper.clearResultMessages();
        mNativeWrapper.onCecMessage(reportPowerStatusTvStandby);
        mTestLooper.dispatchAll();
        assertThat(mPowerManager.isInteractive()).isTrue();

        assertThat(mNativeWrapper.getResultMessages().contains(givePowerStatus)).isTrue();
        // Fourth monitoring cycle: TV reports Standby (2nd consecutive)
        mTestLooper.moveTimeForward(MONITORING_INTERVAL_MS);
        mTestLooper.dispatchAll();
        assertThat(mNativeWrapper.getResultMessages()).contains(givePowerStatus);
        mNativeWrapper.clearResultMessages();
        mNativeWrapper.onCecMessage(reportPowerStatusTvStandby);
        mTestLooper.dispatchAll();

        assertThat(mPowerManager.isInteractive()).isFalse();
        assertThat(mHdmiCecLocalDevicePlayback.getActions(
                PowerStatusMonitorActionFromPlayback.class)).isEmpty();
    }

    private void skipActiveSourceLostUi(long idleDuration, boolean activeSourceLostToTv,