Merge "CEC: Send Active Source as an action" into rvc-dev am: 8d3583e81e

Change-Id: Ia871f7931c05e6fbd3a7a21c0d614637ff4654ea
This commit is contained in:
TreeHugger Robot
2020-05-29 14:08:44 +00:00
committed by Automerger Merge Worker
5 changed files with 330 additions and 31 deletions

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2020 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.hardware.hdmi.HdmiDeviceInfo;
/**
* Action that sends {@code <Active Source>} to make this device the currently active source.
*
* Playback devices will also send {@code <Report Menu Status>} to make them a target for {@code
* <User Control Pressed>} messages.
*/
public class ActiveSourceAction extends HdmiCecFeatureAction {
private static final int STATE_STARTED = 1;
private static final int STATE_FINISHED = 2;
private final int mDestination;
ActiveSourceAction(HdmiCecLocalDevice source, int destination) {
super(source);
mDestination = destination;
}
@Override
boolean start() {
mState = STATE_STARTED;
sendCommand(HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(),
source().mService.getPhysicalAddress()));
if (source().getType() == HdmiDeviceInfo.DEVICE_PLAYBACK) {
// Reports menu-status active to receive <User Control Pressed>.
sendCommand(
HdmiCecMessageBuilder.buildReportMenuStatus(getSourceAddress(), mDestination,
Constants.MENU_STATE_ACTIVATED));
}
mState = STATE_FINISHED;
finish();
return true;
}
@Override
boolean processCommand(HdmiCecMessage cmd) {
return false;
}
@Override
void handleTimerEvent(int state) {
// No response expected
}
}

View File

@@ -251,17 +251,6 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
}
}
@Override
protected void maySendActiveSource(int dest) {
if (mIsActiveSource) {
mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
mAddress, mService.getPhysicalAddress()));
// Always reports menu-status active to receive RCP.
mService.sendCecCommand(HdmiCecMessageBuilder.buildReportMenuStatus(
mAddress, dest, Constants.MENU_STATE_ACTIVATED));
}
}
@ServiceThreadOnly
protected boolean handleSetMenuLanguage(HdmiCecMessage message) {
assertRunOnServiceThread();

View File

@@ -237,10 +237,10 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
}
protected void maySendActiveSource(int dest) {
if (mIsActiveSource) {
mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
mAddress, mService.getPhysicalAddress()));
if (!mIsActiveSource) {
return;
}
addAndStartAction(new ActiveSourceAction(this, dest));
}
/**

View File

@@ -0,0 +1,168 @@
/*
* Copyright (C) 2020 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.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.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 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 ActiveSourceAction} */
@SmallTest
@RunWith(JUnit4.class)
public class ActiveSourceActionTest {
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
PowerManager getPowerManager() {
return powerManager;
}
@Override
void writeStringSystemProperty(String key, String value) {
// do nothing
}
};
Looper looper = mTestLooper.getLooper();
mHdmiControlService.setIoLooper(looper);
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
this.mHdmiControlService, mNativeWrapper);
mHdmiControlService.setCecController(hdmiCecController);
mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
mHdmiControlService.initPortInfo();
mPhysicalAddress = 0x2000;
mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
mTestLooper.dispatchAll();
}
@Test
public void playbackDevice_sendsActiveSource_sendsMenuStatus() {
HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
playbackDevice.init();
mLocalDevices.add(playbackDevice);
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
HdmiCecFeatureAction action = new com.android.server.hdmi.ActiveSourceAction(
playbackDevice, ADDR_TV);
playbackDevice.addAndStartAction(action);
mTestLooper.dispatchAll();
HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
playbackDevice.mAddress, mPhysicalAddress);
HdmiCecMessage menuStatus = HdmiCecMessageBuilder.buildReportMenuStatus(
playbackDevice.mAddress, ADDR_TV, Constants.MENU_STATE_ACTIVATED);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
assertThat(mNativeWrapper.getResultMessages()).contains(menuStatus);
}
@Test
public void audioDevice_sendsActiveSource_noMenuStatus() {
HdmiCecLocalDeviceAudioSystem audioDevice = new HdmiCecLocalDeviceAudioSystem(
mHdmiControlService);
audioDevice.init();
mLocalDevices.add(audioDevice);
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
HdmiCecFeatureAction action = new com.android.server.hdmi.ActiveSourceAction(
audioDevice, ADDR_TV);
audioDevice.addAndStartAction(action);
mTestLooper.dispatchAll();
HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(audioDevice.mAddress,
mPhysicalAddress);
HdmiCecMessage menuStatus = HdmiCecMessageBuilder.buildReportMenuStatus(
audioDevice.mAddress, ADDR_TV, Constants.MENU_STATE_ACTIVATED);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(menuStatus);
}
}

View File

@@ -80,11 +80,21 @@ public class HdmiCecLocalDevicePlaybackTest {
return true;
}
@Override
boolean isPlaybackDevice() {
return true;
}
@Override
void writeStringSystemProperty(String key, String value) {
// do nothing
}
@Override
boolean isPowerStandby() {
return false;
}
@Override
PowerManager getPowerManager() {
return powerManager;
@@ -103,10 +113,10 @@ public class HdmiCecLocalDevicePlaybackTest {
mLocalDevices.add(mHdmiCecLocalDevicePlayback);
mHdmiControlService.initPortInfo();
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
mNativeWrapper.clearResultMessages();
mPlaybackPhysicalAddress = 0x2000;
mNativeWrapper.setPhysicalAddress(mPlaybackPhysicalAddress);
mTestLooper.dispatchAll();
mNativeWrapper.clearResultMessages();
}
// Playback device does not handle routing control related feature right now
@@ -178,8 +188,16 @@ public class HdmiCecLocalDevicePlaybackTest {
mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
mTestLooper.dispatchAll();
assertThat(hasSendKeyAction()).isTrue();
HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(keyPressed);
assertThat(mNativeWrapper.getResultMessages()).contains(keyReleased);
}
@Test
@@ -187,8 +205,16 @@ public class HdmiCecLocalDevicePlaybackTest {
mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, false);
mTestLooper.dispatchAll();
assertThat(hasSendKeyAction()).isTrue();
HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN);
HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(keyPressed);
assertThat(mNativeWrapper.getResultMessages()).contains(keyReleased);
}
@Test
@@ -196,8 +222,16 @@ public class HdmiCecLocalDevicePlaybackTest {
mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, false);
mTestLooper.dispatchAll();
assertThat(hasSendKeyAction()).isTrue();
HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
HdmiCecKeycode.CEC_KEYCODE_MUTE);
HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).contains(keyPressed);
assertThat(mNativeWrapper.getResultMessages()).contains(keyReleased);
}
@Test
@@ -205,8 +239,16 @@ public class HdmiCecLocalDevicePlaybackTest {
mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
mTestLooper.dispatchAll();
assertThat(hasSendKeyAction()).isFalse();
HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyPressed);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyReleased);
}
@Test
@@ -214,8 +256,16 @@ public class HdmiCecLocalDevicePlaybackTest {
mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, false);
mTestLooper.dispatchAll();
assertThat(hasSendKeyAction()).isFalse();
HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyPressed);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyReleased);
}
@Test
@@ -223,18 +273,45 @@ public class HdmiCecLocalDevicePlaybackTest {
mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, false);
mTestLooper.dispatchAll();
assertThat(hasSendKeyAction()).isFalse();
HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyPressed);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyReleased);
}
private boolean hasSendKeyAction() {
boolean match = false;
for (HdmiCecFeatureAction action : mHdmiCecLocalDevicePlayback.mActions) {
if (action instanceof SendKeyAction) {
match = true;
break;
}
}
return match;
@Test
public void handleSetStreamPath_broadcastsActiveSource() {
HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
mPlaybackPhysicalAddress);
mHdmiCecLocalDevicePlayback.dispatchMessage(setStreamPath);
mTestLooper.dispatchAll();
HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
mHdmiCecLocalDevicePlayback.mAddress, mPlaybackPhysicalAddress);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
}
@Test
public void handleSetStreamPath_afterHotplug_broadcastsActiveSource() {
mHdmiControlService.onHotplug(1, false);
mHdmiControlService.onHotplug(1, true);
HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
mPlaybackPhysicalAddress);
mHdmiCecLocalDevicePlayback.dispatchMessage(setStreamPath);
mTestLooper.dispatchAll();
HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(),
mPlaybackPhysicalAddress);
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
}
}