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

Commit 19aad2c9 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Limit power status queries for 2.0 devices on OTP" into sc-dev

parents 4a05d132 7fdfe234
Loading
Loading
Loading
Loading
+32 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
import android.hardware.hdmi.IHdmiControlCallback;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;

/**
 * Feature action that performs one touch play against TV/Display device. This action is initiated
@@ -40,13 +41,15 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction {
    // standby mode, and do not accept the command until their power status becomes 'ON'.
    // For a workaround, we send <Give Device Power Status> commands periodically to make sure
    // the device switches its status to 'ON'. Then we send additional <Active Source>.
    private static final int STATE_WAITING_FOR_REPORT_POWER_STATUS = 1;
    @VisibleForTesting
    static final int STATE_WAITING_FOR_REPORT_POWER_STATUS = 1;

    // The maximum number of times we send <Give Device Power Status> before we give up.
    // We wait up to RESPONSE_TIMEOUT_MS * LOOP_COUNTER_MAX = 20 seconds.
    private static final int LOOP_COUNTER_MAX = 10;

    private final int mTargetAddress;
    private final boolean mIsCec20;

    private int mPowerStatusCounter = 0;

@@ -65,8 +68,19 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction {

    private OneTouchPlayAction(HdmiCecLocalDevice localDevice, int targetAddress,
            IHdmiControlCallback callback) {
        this(localDevice, targetAddress, callback,
                localDevice.getDeviceInfo().getCecVersion()
                        >= HdmiControlManager.HDMI_CEC_VERSION_2_0
                        && localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo(
                        targetAddress).getCecVersion() >= HdmiControlManager.HDMI_CEC_VERSION_2_0);
    }

    @VisibleForTesting
    OneTouchPlayAction(HdmiCecLocalDevice localDevice, int targetAddress,
            IHdmiControlCallback callback, boolean isCec20) {
        super(localDevice, callback);
        mTargetAddress = targetAddress;
        mIsCec20 = isCec20;
    }

    @Override
@@ -74,6 +88,9 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction {
        // Because only source device can create this action, it's safe to cast.
        mSource = source();
        sendCommand(HdmiCecMessageBuilder.buildTextViewOn(getSourceAddress(), mTargetAddress));
        boolean targetOnBefore = localDevice().mService.getHdmiCecNetwork()
                .getCecDeviceInfo(mTargetAddress).getDevicePowerStatus()
                == HdmiControlManager.POWER_STATUS_ON;
        broadcastActiveSource();
        // If the device is not an audio system itself, request the connected audio system to
        // turn on.
@@ -81,7 +98,20 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction {
            sendCommand(HdmiCecMessageBuilder.buildSystemAudioModeRequest(getSourceAddress(),
                    Constants.ADDR_AUDIO_SYSTEM, getSourcePath(), true));
        }
        int targetPowerStatus = localDevice().mService.getHdmiCecNetwork()
                .getCecDeviceInfo(mTargetAddress).getDevicePowerStatus();
        if (!mIsCec20 || targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) {
            queryDevicePowerStatus();
        } else if (targetPowerStatus == HdmiControlManager.POWER_STATUS_ON) {
            if (!targetOnBefore) {
                // Suppress 2nd <Active Source> message if the target device was already on when
                // the 1st one was sent.
                broadcastActiveSource();
            }
            finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
            return true;
        }
        mState = STATE_WAITING_FOR_REPORT_POWER_STATUS;
        addTimer(mState, HdmiConfig.TIMEOUT_MS);
        return true;
    }
@@ -101,7 +131,6 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction {
    }

    private void queryDevicePowerStatus() {
        mState = STATE_WAITING_FOR_REPORT_POWER_STATUS;
        sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(),
                mTargetAddress));
    }
+7 −0
Original line number Diff line number Diff line
@@ -61,6 +61,12 @@ import java.util.concurrent.TimeUnit;
/** Tests for {@link HdmiCecLocalDevicePlayback} class. */
public class HdmiCecLocalDevicePlaybackTest {

    private static final int PORT_1 = 1;
    private static final HdmiDeviceInfo INFO_TV = new HdmiDeviceInfo(
            ADDR_TV, 0x0000, PORT_1, HdmiDeviceInfo.DEVICE_TV,
            0x1234, "TV",
            HdmiControlManager.POWER_STATUS_ON, HdmiControlManager.HDMI_CEC_VERSION_1_4_B);

    private HdmiControlService mHdmiControlService;
    private HdmiCecController mHdmiCecController;
    private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
@@ -159,6 +165,7 @@ public class HdmiCecLocalDevicePlaybackTest {
        mNativeWrapper.setPhysicalAddress(mPlaybackPhysicalAddress);
        mTestLooper.dispatchAll();
        mPlaybackLogicalAddress = mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress();
        mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
        mNativeWrapper.clearResultMessages();
    }

+420 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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 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.OneTouchPlayAction.STATE_WAITING_FOR_REPORT_POWER_STATUS;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.ContextWrapper;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.IHdmiControlCallback;
import android.media.AudioManager;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.Looper;
import android.os.PowerManager;
import android.os.test.TestLooper;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;

import com.android.server.hdmi.HdmiCecFeatureAction.ActionTimer;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;

/** Tests for {@link OneTouchPlayAction} */
@SmallTest
@RunWith(JUnit4.class)
public class OneTouchPlayActionTest {
    private static final byte[] POWER_ON = new byte[]{HdmiControlManager.POWER_STATUS_ON};
    private static final byte[] POWER_TRANSIENT_TO_ON =
            new byte[]{HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON};

    private static final int PORT_1 = 1;
    private static final HdmiDeviceInfo INFO_TV = new HdmiDeviceInfo(
            ADDR_TV, 0x0000, PORT_1, HdmiDeviceInfo.DEVICE_TV,
            0x1234, "TV",
            HdmiControlManager.POWER_STATUS_ON, HdmiControlManager.HDMI_CEC_VERSION_1_4_B);

    private Context mContextSpy;
    private HdmiControlService mHdmiControlService;
    private FakeNativeWrapper mNativeWrapper;

    private TestLooper mTestLooper = new TestLooper();
    private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
    private int mPhysicalAddress;

    @Mock
    private IPowerManager mIPowerManagerMock;
    @Mock
    private IThermalService mIThermalServiceMock;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));

        PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
                mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
        when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
        when(mIPowerManagerMock.isInteractive()).thenReturn(true);

        mHdmiControlService = new HdmiControlService(mContextSpy) {
            @Override
            AudioManager getAudioManager() {
                return new AudioManager() {
                    @Override
                    public void setWiredDeviceConnectionState(
                            int type, int state, String address, String name) {
                        // Do nothing.
                    }
                };
            }

            @Override
            void wakeUp() {
            }

            @Override
            boolean isPowerStandby() {
                return false;
            }

            @Override
            protected PowerManager getPowerManager() {
                return powerManager;
            }

            @Override
            protected void writeStringSystemProperty(String key, String value) {
                // do nothing
            }
        };

        Looper looper = mTestLooper.getLooper();
        mHdmiControlService.setIoLooper(looper);
        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
        mNativeWrapper = new FakeNativeWrapper();
        HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
        mHdmiControlService.setCecController(hdmiCecController);
        mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
        mHdmiControlService.initService();
        mPhysicalAddress = 0x2000;
        mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
        mTestLooper.dispatchAll();
        mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
    }

    private OneTouchPlayAction createOneTouchPlayAction(HdmiCecLocalDevicePlayback device,
            TestActionTimer actionTimer, TestCallback callback, boolean isCec20) {
        OneTouchPlayAction action = new OneTouchPlayAction(device, ADDR_TV, callback, isCec20);
        action.setActionTimer(actionTimer);
        return action;
    }

    @Test
    public void succeedAfterGettingPowerStatusOn_Cec14b() {
        HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
                mHdmiControlService);
        playbackDevice.init();
        mLocalDevices.add(playbackDevice);
        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
        mTestLooper.dispatchAll();

        TestActionTimer actionTimer = new TestActionTimer();
        TestCallback callback = new TestCallback();
        OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback,
                false);
        playbackDevice.addAndStartAction(action);
        mTestLooper.dispatchAll();

        HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
                playbackDevice.mAddress, mPhysicalAddress);
        HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
                ADDR_TV);
        HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
                .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);

        assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
        assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
        assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
        mNativeWrapper.clearResultMessages();
        assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS);
        HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage(
                ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON);
        action.processCommand(reportPowerStatusOn);
        mTestLooper.dispatchAll();

        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
        assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus);
        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
    }

    @Test
    public void succeedAfterGettingTransientPowerStatus_Cec14b() {
        HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
                mHdmiControlService);
        playbackDevice.init();
        mLocalDevices.add(playbackDevice);
        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
        mTestLooper.dispatchAll();

        TestActionTimer actionTimer = new TestActionTimer();
        TestCallback callback = new TestCallback();
        OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback,
                false);
        playbackDevice.addAndStartAction(action);
        mTestLooper.dispatchAll();

        HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
                playbackDevice.mAddress, mPhysicalAddress);
        HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
                ADDR_TV);
        HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
                .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);

        assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
        assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
        assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
        mNativeWrapper.clearResultMessages();
        assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS);
        HdmiCecMessage reportPowerStatusTransientToOn = new HdmiCecMessage(
                ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS,
                POWER_TRANSIENT_TO_ON);
        action.processCommand(reportPowerStatusTransientToOn);
        action.handleTimerEvent(STATE_WAITING_FOR_REPORT_POWER_STATUS);
        mTestLooper.dispatchAll();

        assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
        mNativeWrapper.clearResultMessages();

        HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage(
                ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON);
        action.processCommand(reportPowerStatusOn);
        mTestLooper.dispatchAll();

        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
        assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus);
        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
    }

    @Test
    public void timeOut_Cec14b() {
        HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
                mHdmiControlService);
        playbackDevice.init();
        mLocalDevices.add(playbackDevice);
        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
        mTestLooper.dispatchAll();

        TestActionTimer actionTimer = new TestActionTimer();
        TestCallback callback = new TestCallback();
        OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback,
                false);
        playbackDevice.addAndStartAction(action);
        mTestLooper.dispatchAll();

        HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
                playbackDevice.mAddress, mPhysicalAddress);
        HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
                ADDR_TV);
        HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
                .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);

        assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
        assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
        assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
        mNativeWrapper.clearResultMessages();
        assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS);
        for (int i = 0; i < 10; ++i) {
            action.handleTimerEvent(STATE_WAITING_FOR_REPORT_POWER_STATUS);
            mTestLooper.dispatchAll();
        }

        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSource);
        assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
        action.handleTimerEvent(STATE_WAITING_FOR_REPORT_POWER_STATUS);
        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TIMEOUT);
    }

    @Test
    public void succeedIfPowerStatusOn_Cec20() {
        HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
                mHdmiControlService);
        playbackDevice.init();
        mLocalDevices.add(playbackDevice);
        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
        mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_TV,
                HdmiControlManager.POWER_STATUS_ON);
        mTestLooper.dispatchAll();

        TestActionTimer actionTimer = new TestActionTimer();
        TestCallback callback = new TestCallback();
        OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback,
                true);
        playbackDevice.addAndStartAction(action);
        mTestLooper.dispatchAll();

        HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
                playbackDevice.mAddress, mPhysicalAddress);
        HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
                ADDR_TV);
        HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
                .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);

        assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
        assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus);
        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
    }

    @Test
    public void succeedIfPowerStatusUnknown_Cec20() {
        HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
                mHdmiControlService);
        playbackDevice.init();
        mLocalDevices.add(playbackDevice);
        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
        mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_TV,
                HdmiControlManager.POWER_STATUS_UNKNOWN);
        mTestLooper.dispatchAll();

        TestActionTimer actionTimer = new TestActionTimer();
        TestCallback callback = new TestCallback();
        OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback,
                true);
        playbackDevice.addAndStartAction(action);
        mTestLooper.dispatchAll();

        HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
                playbackDevice.mAddress, mPhysicalAddress);
        HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
                ADDR_TV);
        HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
                .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);

        assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
        assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
        assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
        mNativeWrapper.clearResultMessages();
        assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS);
        HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage(
                ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON);
        action.processCommand(reportPowerStatusOn);
        mTestLooper.dispatchAll();

        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
        assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus);
        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
    }

    @Test
    public void succeedIfPowerStatusStandby_Cec20() {
        HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
                mHdmiControlService);
        playbackDevice.init();
        mLocalDevices.add(playbackDevice);
        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
        mHdmiControlService.getHdmiCecNetwork().updateDevicePowerStatus(ADDR_TV,
                HdmiControlManager.POWER_STATUS_STANDBY);
        mTestLooper.dispatchAll();

        TestActionTimer actionTimer = new TestActionTimer();
        TestCallback callback = new TestCallback();
        OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback,
                true);
        playbackDevice.addAndStartAction(action);
        mTestLooper.dispatchAll();

        HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
                playbackDevice.mAddress, mPhysicalAddress);
        HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
                ADDR_TV);
        HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
                .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);

        assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
        assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus);
        mNativeWrapper.clearResultMessages();
        assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS);
        HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage(
                ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON);
        action.processCommand(reportPowerStatusOn);
        mTestLooper.dispatchAll();

        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
        assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus);
        assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
    }

    private static class TestActionTimer implements ActionTimer {
        private int mState;

        @Override
        public void sendTimerMessage(int state, long delayMillis) {
            mState = state;
        }

        @Override
        public void clearTimerMessage() {
        }

        private int getState() {
            return mState;
        }
    }

    private static class TestCallback extends IHdmiControlCallback.Stub {
        private final ArrayList<Integer> mCallbackResult = new ArrayList<Integer>();

        @Override
        public void onComplete(int result) {
            mCallbackResult.add(result);
        }

        private int getResult() {
            assertThat(mCallbackResult.size()).isEqualTo(1);
            return mCallbackResult.get(0);
        }
    }
}