summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2020-05-29 13:52:50 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-05-29 13:52:50 +0000
commit8d3583e81ea5879602a32b857d3b266ce7d11603 (patch)
tree616a138a991201fa6e2558b20bea7e86dd27a8d0
parentd220529254c319dba900258f13ba8441f7262eaa (diff)
parent281db8f6ddc7a68328694abece06d2914324b4ad (diff)
Merge "CEC: Send Active Source as an action" into rvc-dev
-rw-r--r--services/core/java/com/android/server/hdmi/ActiveSourceAction.java65
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java11
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java168
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java111
5 files changed, 330 insertions, 31 deletions
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceAction.java b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
new file mode 100644
index 000000000000..3c4dae0f6467
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
@@ -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
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 67861c28b37e..d6993b2b38e9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -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();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index ae008b4bfa7a..df6b40dbbcb8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -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));
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
new file mode 100644
index 000000000000..50086affcbc5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -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);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index b76211895ab0..145e1ec56e4a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -81,11 +81,21 @@ public class HdmiCecLocalDevicePlaybackTest {
}
@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();
+
+ HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
- assertThat(hasSendKeyAction()).isTrue();
+ 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();
+
+ HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN);
+ HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
- assertThat(hasSendKeyAction()).isTrue();
+ 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();
+
+ HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_MUTE);
+ HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
- assertThat(hasSendKeyAction()).isTrue();
+ 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();
+
+ HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV,
+ HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+ HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
- assertThat(hasSendKeyAction()).isFalse();
+ 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);
}
}