diff options
7 files changed, 96 insertions, 16 deletions
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java index c23e2e691b55..947ee24f8e02 100644 --- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java +++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java @@ -97,11 +97,16 @@ final class DeviceSelectAction extends HdmiCecFeatureAction { @Override public boolean start() { - // Wake-up on <Set Stream Path> was not mandatory before CEC 2.0. - // The message is re-sent at the end of the action for devices that don't support 2.0. - sendSetStreamPath(); - int targetPowerStatus = localDevice().mService.getHdmiCecNetwork() - .getCecDeviceInfo(getTargetAddress()).getDevicePowerStatus(); + // Wake-up on <Set Stream Path> was not mandatory before CEC 2.0. + // The message is re-sent at the end of the action for devices that don't support 2.0. + sendSetStreamPath(); + int targetPowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN; + HdmiDeviceInfo targetDevice = localDevice().mService.getHdmiCecNetwork().getCecDeviceInfo( + getTargetAddress()); + if (targetDevice != null) { + targetPowerStatus = targetDevice.getDevicePowerStatus(); + } + if (!mIsCec20 || targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) { queryDevicePowerStatus(); } else if (targetPowerStatus == HdmiControlManager.POWER_STATUS_ON) { diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index d8914b389191..bdc4e66cf7f9 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -500,7 +500,8 @@ abstract class HdmiCecLocalDevice { HdmiDeviceInfo cecDeviceInfo = mService.getHdmiCecNetwork().getCecDeviceInfo(address); // If no non-default display name is available for the device, request the devices OSD name. - if (cecDeviceInfo.getDisplayName().equals(HdmiUtils.getDefaultDeviceName(address))) { + if (cecDeviceInfo != null && cecDeviceInfo.getDisplayName().equals( + HdmiUtils.getDefaultDeviceName(address))) { mService.sendCecCommand( HdmiCecMessageBuilder.buildGiveOsdNameCommand(mAddress, address)); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 7235a921254d..90d64339eac0 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -30,6 +30,7 @@ import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_ANAL import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL; import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL; +import android.annotation.Nullable; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiPortInfo; @@ -1147,6 +1148,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { && getAvrDeviceInfo() != null; } + @Nullable @ServiceThreadOnly HdmiDeviceInfo getAvrDeviceInfo() { assertRunOnServiceThread(); @@ -1157,6 +1159,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return getSafeAvrDeviceInfo() != null; } + @Nullable HdmiDeviceInfo getSafeAvrDeviceInfo() { return mService.getHdmiCecNetwork().getSafeCecDeviceInfo(Constants.ADDR_AUDIO_SYSTEM); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java index b748ae026cfc..7ceaa959212e 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java @@ -185,6 +185,12 @@ public class HdmiCecNetwork { mLocalDevices.clear(); } + /** + * Get the device info of a local device or a device in the CEC network by a device id. + * @param id id of the device to get + * @return the device with the given id, or {@code null} + */ + @Nullable public HdmiDeviceInfo getDeviceInfo(int id) { return mDeviceInfos.get(id); } @@ -717,6 +723,7 @@ public class HdmiCecNetwork { * @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}. * Returns null if no logical address matched */ + @Nullable HdmiDeviceInfo getSafeCecDeviceInfo(int logicalAddress) { for (HdmiDeviceInfo info : mSafeAllDeviceInfos) { if (info.isCecDevice() && info.getLogicalAddress() == logicalAddress) { diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 115cafedca93..e6e2f9631d45 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -988,6 +988,7 @@ public class HdmiControlService extends SystemService { return mCecController.getVendorId(); } + @Nullable @ServiceThreadOnly HdmiDeviceInfo getDeviceInfo(int logicalAddress) { assertRunOnServiceThread(); diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java index 73ecbe0432b7..9d2db94cac8e 100644 --- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java +++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java @@ -16,6 +16,7 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiControlManager; +import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback; import android.hardware.hdmi.IHdmiControlCallback; import android.util.Slog; @@ -62,8 +63,7 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { Slog.e(TAG, "Wrong arguments"); return null; } - return new OneTouchPlayAction(source, targetAddress, - callback); + return new OneTouchPlayAction(source, targetAddress, callback); } private OneTouchPlayAction(HdmiCecLocalDevice localDevice, int targetAddress, @@ -71,8 +71,8 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { 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); + && getTargetCecVersion(localDevice, targetAddress) + >= HdmiControlManager.HDMI_CEC_VERSION_2_0); } @VisibleForTesting @@ -88,9 +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; + + boolean targetOnBefore = getTargetDevicePowerStatus(mSource, mTargetAddress, + HdmiControlManager.POWER_STATUS_UNKNOWN) == HdmiControlManager.POWER_STATUS_ON; broadcastActiveSource(); // If the device is not an audio system itself, request the connected audio system to // turn on. @@ -98,8 +98,8 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { sendCommand(HdmiCecMessageBuilder.buildSystemAudioModeRequest(getSourceAddress(), Constants.ADDR_AUDIO_SYSTEM, getSourcePath(), true)); } - int targetPowerStatus = localDevice().mService.getHdmiCecNetwork() - .getCecDeviceInfo(mTargetAddress).getDevicePowerStatus(); + int targetPowerStatus = getTargetDevicePowerStatus(mSource, mTargetAddress, + HdmiControlManager.POWER_STATUS_UNKNOWN); if (!mIsCec20 || targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) { queryDevicePowerStatus(); } else if (targetPowerStatus == HdmiControlManager.POWER_STATUS_ON) { @@ -179,4 +179,23 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { return sendStandbyOnSleep.equals(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST); } + private static int getTargetCecVersion(HdmiCecLocalDevice localDevice, + int targetLogicalAddress) { + HdmiDeviceInfo targetDevice = localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo( + targetLogicalAddress); + if (targetDevice != null) { + return targetDevice.getCecVersion(); + } + return HdmiControlManager.HDMI_CEC_VERSION_1_4_B; + } + + private static int getTargetDevicePowerStatus(HdmiCecLocalDevice localDevice, + int targetLogicalAddress, int defaultPowerStatus) { + HdmiDeviceInfo targetDevice = localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo( + targetLogicalAddress); + if (targetDevice != null) { + return targetDevice.getDevicePowerStatus(); + } + return defaultPowerStatus; + } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java index 907cf3eb1f70..c61635cbd4b6 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java @@ -136,7 +136,6 @@ public class OneTouchPlayActionTest { mPhysicalAddress = 0x2000; mNativeWrapper.setPhysicalAddress(mPhysicalAddress); mTestLooper.dispatchAll(); - mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); } private OneTouchPlayAction createOneTouchPlayAction(HdmiCecLocalDevicePlayback device, @@ -147,7 +146,47 @@ public class OneTouchPlayActionTest { } @Test + public void succeedWithUnknownTvDevice() { + 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 succeedAfterGettingPowerStatusOn_Cec14b() { + mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback( mHdmiControlService); playbackDevice.init(); @@ -187,6 +226,7 @@ public class OneTouchPlayActionTest { @Test public void succeedAfterGettingTransientPowerStatus_Cec14b() { + mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback( mHdmiControlService); playbackDevice.init(); @@ -236,6 +276,7 @@ public class OneTouchPlayActionTest { @Test public void timeOut_Cec14b() { + mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback( mHdmiControlService); playbackDevice.init(); @@ -276,6 +317,7 @@ public class OneTouchPlayActionTest { @Test public void succeedIfPowerStatusOn_Cec20() { + mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback( mHdmiControlService); playbackDevice.init(); @@ -307,6 +349,7 @@ public class OneTouchPlayActionTest { @Test public void succeedIfPowerStatusUnknown_Cec20() { + mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback( mHdmiControlService); playbackDevice.init(); @@ -348,6 +391,7 @@ public class OneTouchPlayActionTest { @Test public void succeedIfPowerStatusStandby_Cec20() { + mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV); HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback( mHdmiControlService); playbackDevice.init(); |