From ec126a57f3a8a4c9150a01e3bd0d0dfa5e04cd0a Mon Sep 17 00:00:00 2001 From: Amy Date: Tue, 30 Oct 2018 16:51:14 -0700 Subject: [PATCH 1/8] Add a thread safe copy of connected device list. ag/5398140 We are adding a thread safe list of the devices connected to the current device. Also adding some methods to update/get the list. HdmiControlService can call to get the list and the information. Test: local tested. Change-Id: I25715065c744a976bcf0d038cbe8568d8c44d0f9 --- .../hdmi/HdmiCecLocalDeviceAudioSystem.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index 5c1b3deb99556..f94d9a5a07e16 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -45,6 +45,7 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; @@ -84,6 +85,10 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { // processing. private final HashMap mTvInputs = new HashMap<>(); + // Copy of mDeviceInfos to guarantee thread-safety. + @GuardedBy("mLock") + private List mSafeAllDeviceInfos = Collections.emptyList(); + // Map-like container of all cec devices. // device id is used as key of container. private final SparseArray mDeviceInfos = new SparseArray<>(); @@ -174,6 +179,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { removeDeviceInfo(deviceInfo.getId()); } mDeviceInfos.append(deviceInfo.getId(), deviceInfo); + updateSafeDeviceInfoList(); return oldDeviceInfo; } @@ -191,6 +197,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { if (deviceInfo != null) { mDeviceInfos.remove(id); } + updateSafeDeviceInfoList(); return deviceInfo; } @@ -207,6 +214,24 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { return mDeviceInfos.get(HdmiDeviceInfo.idForCecDevice(logicalAddress)); } + @ServiceThreadOnly + private void updateSafeDeviceInfoList() { + assertRunOnServiceThread(); + List copiedDevices = HdmiUtils.sparseArrayToList(mDeviceInfos); + synchronized (mLock) { + mSafeAllDeviceInfos = copiedDevices; + } + } + + @GuardedBy("mLock") + List getSafeCecDevicesLocked() { + ArrayList infoList = new ArrayList<>(); + for (HdmiDeviceInfo info : mSafeAllDeviceInfos) { + infoList.add(info); + } + return infoList; + } + private void invokeDeviceEventListener(HdmiDeviceInfo info, int status) { mService.invokeDeviceEventListeners(info, status); } @@ -1086,6 +1111,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE); } mDeviceInfos.clear(); + updateSafeDeviceInfoList(); } @Override From 77e672c7da1e69e889c28109091a17304132daa4 Mon Sep 17 00:00:00 2001 From: Amy Date: Wed, 31 Oct 2018 15:55:40 -0700 Subject: [PATCH 2/8] Set routing feature enabled to default false and dump its status. ag/5408510 We set HDMI_CEC_SWITCH_ENABLED to default false to avoid switching behavior at device set up stage. It should be set to true when device is ready to switch. Bug:116850696 Test: local tested Change-Id: I3d08c9757c2a604294dae34103222e482088aec0 --- .../com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java | 3 ++- .../java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index f94d9a5a07e16..614e338b17b8f 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -96,7 +96,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); mRoutingControlFeatureEnabled = - mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, true); + mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, false); mSystemAudioControlFeatureEnabled = mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true); // TODO(amyjojo): make the map ro property. @@ -1119,6 +1119,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { pw.println("HdmiCecLocalDeviceAudioSystem:"); pw.increaseIndent(); pw.println("mSystemAudioActivated: " + mSystemAudioActivated); + pw.println("isRoutingFeatureEnabled " + isRoutingControlFeatureEnabled()); pw.println("mSystemAudioControlFeatureEnabled: " + mSystemAudioControlFeatureEnabled); pw.println("mTvSystemAudioModeSupport: " + mTvSystemAudioModeSupport); pw.println("mArcEstablished: " + mArcEstablished); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java index cbddaf53348a2..83c2fe12e4620 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java @@ -66,7 +66,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice { @LocalActivePort protected int mLocalActivePort = Constants.CEC_SWITCH_HOME; - // Whether the Routing Coutrol feature is enabled or not. True by default. + // Whether the Routing Coutrol feature is enabled or not. False by default. @GuardedBy("mLock") protected boolean mRoutingControlFeatureEnabled; From 2e4b25c4c7f6c9df29925a78bcd7149b75bde48a Mon Sep 17 00:00:00 2001 From: Amy Date: Tue, 30 Oct 2018 18:08:49 -0700 Subject: [PATCH 3/8] Add dump info of local active port and routing port. ag/5396281 Test: local tested Change-Id: If657c70b371be8e1b9e4cbb54a80a17e154cdf3a --- .../com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index 614e338b17b8f..a8256e74b47f2 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -1124,6 +1124,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { pw.println("mTvSystemAudioModeSupport: " + mTvSystemAudioModeSupport); pw.println("mArcEstablished: " + mArcEstablished); pw.println("mArcIntentUsed: " + mArcIntentUsed); + pw.println("mRoutingPort: " + getRoutingPort()); + pw.println("mLocalActivePort: " + getLocalActivePort()); HdmiUtils.dumpMap(pw, "mTvInputs:", mTvInputs); HdmiUtils.dumpSparseArray(pw, "mDeviceInfos:", mDeviceInfos); pw.decreaseIndent(); From 0063811f183504f286e5e731cee85ab7069fd121 Mon Sep 17 00:00:00 2001 From: Amy Date: Wed, 31 Oct 2018 17:47:17 -0700 Subject: [PATCH 4/8] Fix port id mismatch temporarily. ag/5409198 On Atom, HDMI1 port id is 2. HDMI2 is 4. HDMI3 is 1. They are different from the port index. When we do manual switch, we use port id to set Routing Port. When we receive ActiveSource/SetStreamPath, we use port index. There is a mismatch right now before we transit from hard code to a portid-tvinputid mapping. Note this is a temporary solution to avoid potential bug. Test: manual. Change-Id: I949587e17b815a755abf7cb17a70da1262efcd70 --- .../hdmi/HdmiCecLocalDeviceAudioSystem.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index a8256e74b47f2..4fc98f8227213 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -99,13 +99,10 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, false); mSystemAudioControlFeatureEnabled = mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true); - // TODO(amyjojo): make the map ro property. - mTvInputs.put(Constants.CEC_SWITCH_HDMI1, - "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5"); - mTvInputs.put(Constants.CEC_SWITCH_HDMI2, - "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6"); - mTvInputs.put(Constants.CEC_SWITCH_HDMI3, - "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7"); + // TODO(amyjojo): Maintain a portId to TvinputId map. + mTvInputs.put(2, "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5"); + mTvInputs.put(4, "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6"); + mTvInputs.put(1, "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7"); } /** @@ -748,7 +745,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { */ private void setSystemAudioMode(boolean newSystemAudioMode) { int targetPhysicalAddress = getActiveSource().physicalAddress; - int port = getLocalPortFromPhysicalAddress(targetPhysicalAddress); + int port = mService.pathToPortId(targetPhysicalAddress); if (newSystemAudioMode && port >= 0) { switchToAudioInput(); } @@ -947,7 +944,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { @Override protected void switchInputOnReceivingNewActivePath(int physicalAddress) { - int port = getLocalPortFromPhysicalAddress(physicalAddress); + int port = mService.pathToPortId(physicalAddress); if (isSystemAudioActivated() && port < 0) { // If system audio mode is on and the new active source is not under the current device, // Will switch to ARC input. @@ -1019,7 +1016,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { @Override protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) { - int port = getLocalPortFromPhysicalAddress(physicalAddress); + int port = mService.pathToPortId(physicalAddress); // Routing change or information sent from switches under the current device can be ignored. if (port > 0) { return; From 6f031afecf1e73ee2d41262d009cf9143db95dc0 Mon Sep 17 00:00:00 2001 From: Amy Date: Tue, 30 Oct 2018 16:38:33 -0700 Subject: [PATCH 5/8] Add APIs to expose some cec control to other services. ag/5398143 We exposed Power on/Power off/Device select/Connected device list query from HdmiControlManager. Test: local tested Bug: 117775357 Change-Id: Iee495e7131f44282a60e83ad827faa1431a30389 --- .../hardware/hdmi/HdmiControlManager.java | 68 ++++++++++++++++ .../hardware/hdmi/IHdmiControlService.aidl | 3 + .../hdmi/HdmiAudioSystemClientTest.java | 12 +++ .../server/hdmi/HdmiControlService.java | 81 ++++++++++++++++++- 4 files changed, 161 insertions(+), 3 deletions(-) diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java index be8009e6a9661..a7734f5446076 100644 --- a/core/java/android/hardware/hdmi/HdmiControlManager.java +++ b/core/java/android/hardware/hdmi/HdmiControlManager.java @@ -33,6 +33,8 @@ import android.os.SystemProperties; import android.util.ArrayMap; import android.util.Log; +import java.util.List; + /** * The {@link HdmiControlManager} class is used to send HDMI control messages * to attached CEC devices. @@ -403,6 +405,72 @@ public final class HdmiControlManager { return (HdmiSwitchClient) getClient(HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH); } + /** + * Get a snapshot of the real-time status of the remote devices. + * + * @return a list of {@link HdmiDeviceInfo} of the devices connected to the current device. + * + * TODO(b/110094868): unhide for Q + * @hide + */ + public List getConnectedDevicesList() { + try { + return mService.getDeviceList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Power off the target device. + * + * @param deviceInfo HdmiDeviceInfo of the device to be powered off + * + * TODO(b/110094868): unhide for Q + * @hide + */ + public void powerOffRemoteDevice(HdmiDeviceInfo deviceInfo) { + try { + mService.powerOffRemoteDevice( + deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Power on the target device. + * + * @param deviceInfo HdmiDeviceInfo of the device to be powered on + * + * TODO(b/110094868): unhide for Q + * @hide + */ + public void powerOnRemoteDevice(HdmiDeviceInfo deviceInfo) { + try { + mService.powerOnRemoteDevice( + deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Ask the target device to be the new Active Source. + * + * @param deviceInfo HdmiDeviceInfo of the target device + * + * TODO(b/110094868): unhide for Q + * @hide + */ + public void askRemoteDeviceToBecomeActiveSource(HdmiDeviceInfo deviceInfo) { + try { + mService.askRemoteDeviceToBecomeActiveSource(deviceInfo.getPhysicalAddress()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Controls standby mode of the system. It will also try to turn on/off the connected devices if * necessary. diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl index 66bb084d5482f..1cd9920aa250f 100644 --- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl +++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl @@ -61,6 +61,9 @@ interface IHdmiControlService { void setInputChangeListener(IHdmiInputChangeListener listener); List getInputDevices(); List getDeviceList(); + void powerOffRemoteDevice(int logicalAddress, int powerStatus); + void powerOnRemoteDevice(int logicalAddress, int powerStatus); + void askRemoteDeviceToBecomeActiveSource(int physicalAddress); void sendVendorCommand(int deviceType, int targetAddress, in byte[] params, boolean hasVendorId); void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType); diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java index 64b3ba04e841d..28a8afe434e4d 100644 --- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java +++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java @@ -327,6 +327,18 @@ public class HdmiAudioSystemClientTest { public int getPhysicalAddress() { return 0x0000; } + + @Override + public void powerOffRemoteDevice(int logicalAddress, int powerStatus) { + } + + @Override + public void powerOnRemoteDevice(int logicalAddress, int powerStatus) { + } + + @Override + public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) { + } } } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index aabe1ad659d6a..d390d860aeeae 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -20,6 +20,7 @@ import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE; import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE; import static com.android.internal.os.RoSystemProperties.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH; +import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED; import static com.android.server.hdmi.Constants.DISABLED; import static com.android.server.hdmi.Constants.ENABLED; import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE; @@ -1615,13 +1616,64 @@ public class HdmiControlService extends SystemService { public List getDeviceList() { enforceAccessPermission(); HdmiCecLocalDeviceTv tv = tv(); - synchronized (mLock) { - return (tv == null) + if (tv != null) { + synchronized (mLock) { + return tv.getSafeCecDevicesLocked(); + } + } else { + HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem(); + synchronized (mLock) { + return (audioSystem == null) ? Collections.emptyList() - : tv.getSafeCecDevicesLocked(); + : audioSystem.getSafeCecDevicesLocked(); + } } } + @Override + public void powerOffRemoteDevice(int logicalAddress, int powerStatus) { + enforceAccessPermission(); + runOnServiceThread(new Runnable() { + @Override + public void run() { + if (powerStatus == HdmiControlManager.POWER_STATUS_ON + || powerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { + sendCecCommand(HdmiCecMessageBuilder.buildStandby( + getRemoteControlSourceAddress(), logicalAddress)); + } else { + Slog.w(TAG, "Device " + logicalAddress + " is already off " + powerStatus); + } + } + }); + } + + @Override + public void powerOnRemoteDevice(int logicalAddress, int powerStatus) { + // TODO(amyjojo): implement the method + } + + @Override + // TODO(AMYJOJO): add a result callback + public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) { + enforceAccessPermission(); + runOnServiceThread(new Runnable() { + @Override + public void run() { + HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath( + getRemoteControlSourceAddress(), physicalAddress); + if (pathToPortId(physicalAddress) != Constants.INVALID_PORT_ID) { + if (getSwitchDevice() != null) { + getSwitchDevice().handleSetStreamPath(setStreamPath); + } else { + Slog.e(TAG, "Can't get the correct local device to handle routing."); + } + } else { + sendCecCommand(setStreamPath); + } + } + }); + } + @Override public void setSystemAudioVolume(final int oldIndex, final int newIndex, final int maxIndex) { @@ -1917,6 +1969,29 @@ public class HdmiControlService extends SystemService { } } + // Get the source address to send out commands to devices connected to the current device + // when other services interact with HdmiControlService. + private int getRemoteControlSourceAddress() { + if (isAudioSystemDevice()) { + return audioSystem().getDeviceInfo().getLogicalAddress(); + } else if (isPlaybackDevice()) { + return playback().getDeviceInfo().getLogicalAddress(); + } + return ADDR_UNREGISTERED; + } + + // Get the switch device to do CEC routing control + @Nullable + private HdmiCecLocalDeviceSource getSwitchDevice() { + if (isAudioSystemDevice()) { + return audioSystem(); + } + if (isPlaybackDevice()) { + return playback(); + } + return null; + } + @ServiceThreadOnly private void oneTouchPlay(final IHdmiControlCallback callback) { assertRunOnServiceThread(); From 51c6a63eeee317af7f2ebbaf1ff837fd40bd2942 Mon Sep 17 00:00:00 2001 From: Amy Date: Tue, 23 Oct 2018 20:13:19 -0700 Subject: [PATCH 6/8] Make sure the device route to HOME when OneTouchPlay is triggered. ag/5342226 Note that we still need to discuss if this is the expected bahavior. For example when the device was on HDMI2 before TV button is pressed to turn TV off. When user press TV button again to turn TV on, should the device trigger OneTouch to grab Active Source or stay in the same input. Right now it trigger One Touch so it should route back to Home. Test: local tested. Bug: 118352291 Change-Id: I9f9a5f461063d872509764339503933e0f22aa8f --- .../core/java/com/android/server/hdmi/OneTouchPlayAction.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java index 41bf01f842cd4..d665efe5a4e94 100644 --- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java +++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java @@ -92,6 +92,9 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { if (source.mService.audioSystem() != null) { source = source.mService.audioSystem(); } + if (source.getLocalActivePort() != Constants.CEC_SWITCH_HOME) { + source.switchInputOnReceivingNewActivePath(getSourceAddress()); + } source.setRoutingPort(Constants.CEC_SWITCH_HOME); source.setLocalActivePort(Constants.CEC_SWITCH_HOME); } From 61fc25f7b417ffa3d53f9adfd07810d326dd2bcc Mon Sep 17 00:00:00 2001 From: Amy Date: Fri, 2 Nov 2018 17:53:21 -0700 Subject: [PATCH 7/8] Unmute when turning system audio mode on. ag/5428480 This is useful for devices that disables muting. When TV sends out muting to the device but the device later turns system audio mode back on, it should still unmute itself. Disabling muting should only disable self mute. But still support unmute. Test: manual Bug: 118890232 Change-Id: Ief4435c786262a1981a29627b837ef0a4831157a --- .../hdmi/HdmiCecLocalDeviceAudioSystem.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index 4fc98f8227213..c9eef0f5fbb76 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -753,16 +753,18 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { // PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE is false when device never needs to be muted. boolean currentMuteStatus = mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC); - if (SystemProperties.getBoolean( - Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, true) - && currentMuteStatus == newSystemAudioMode) { - mService.getAudioManager() - .adjustStreamVolume( - AudioManager.STREAM_MUSIC, - newSystemAudioMode - ? AudioManager.ADJUST_UNMUTE - : AudioManager.ADJUST_MUTE, - 0); + if (currentMuteStatus == newSystemAudioMode) { + if (SystemProperties.getBoolean( + Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, true) + || newSystemAudioMode) { + mService.getAudioManager() + .adjustStreamVolume( + AudioManager.STREAM_MUSIC, + newSystemAudioMode + ? AudioManager.ADJUST_UNMUTE + : AudioManager.ADJUST_MUTE, + 0); + } } updateAudioManagerForSystemAudio(newSystemAudioMode); synchronized (mLock) { From 47fe0b16865a0f529be5771ffccdba2c4d542c1c Mon Sep 17 00:00:00 2001 From: Amy Date: Tue, 6 Nov 2018 14:45:18 -0800 Subject: [PATCH 8/8] Add Power Status query steps in Device Discovery Action. ag/5451608 Test: manual Bug: 113071437 Change-Id: Idebffbec8f49c9e396f382ae04fbbc1ef4a20dac --- .../server/hdmi/DeviceDiscoveryAction.java | 73 ++++++++++++++++++- .../hdmi/HdmiCecLocalDeviceAudioSystem.java | 4 + 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java index af716242210ed..d137580e9eea4 100755 --- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java +++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java @@ -16,6 +16,7 @@ package com.android.server.hdmi; +import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.util.Slog; @@ -51,8 +52,10 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction { private static final int STATE_WAITING_FOR_OSD_NAME = 3; // State in which the action is waiting for gathering vendor id of non-local devices. private static final int STATE_WAITING_FOR_VENDOR_ID = 4; - // State in which the action is waiting for devices to be ready + // State in which the action is waiting for devices to be ready. private static final int STATE_WAITING_FOR_DEVICES = 5; + // State in which the action is waiting for gathering power status of non-local devices. + private static final int STATE_WAITING_FOR_POWER = 6; /** * Interface used to report result of device discovery. @@ -74,6 +77,7 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction { private int mPhysicalAddress = Constants.INVALID_PHYSICAL_ADDRESS; private int mPortId = Constants.INVALID_PORT_ID; private int mVendorId = Constants.UNKNOWN_VENDOR_ID; + private int mPowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN; private String mDisplayName = ""; private int mDeviceType = HdmiDeviceInfo.DEVICE_INACTIVE; @@ -83,7 +87,7 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction { private HdmiDeviceInfo toHdmiDeviceInfo() { return new HdmiDeviceInfo(mLogicalAddress, mPhysicalAddress, mPortId, mDeviceType, - mVendorId, mDisplayName); + mVendorId, mDisplayName, mPowerStatus); } } @@ -237,6 +241,29 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction { addTimer(mState, HdmiConfig.TIMEOUT_MS); } + private void startPowerStatusStage() { + Slog.v(TAG, "Start [Power Status Stage]:" + mDevices.size()); + mProcessedDeviceCount = 0; + mState = STATE_WAITING_FOR_POWER; + + checkAndProceedStage(); + } + + private void queryPowerStatus(int address) { + if (!verifyValidLogicalAddress(address)) { + checkAndProceedStage(); + return; + } + + mActionTimer.clearTimerMessage(); + + if (mayProcessMessageIfCached(address, Constants.MESSAGE_REPORT_POWER_STATUS)) { + return; + } + sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), address)); + addTimer(mState, HdmiConfig.TIMEOUT_MS); + } + private boolean mayProcessMessageIfCached(int address, int opcode) { HdmiCecMessage message = getCecMessageCache().getMessage(address, opcode); if (message != null) { @@ -275,6 +302,16 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction { return true; } return false; + case STATE_WAITING_FOR_POWER: + if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) { + handleReportPowerStatus(cmd); + return true; + } else if ((cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT) + && ((cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_REPORT_POWER_STATUS)) { + handleReportPowerStatus(cmd); + return true; + } + return false; case STATE_WAITING_FOR_DEVICE_POLLING: // Fall through. default: @@ -359,6 +396,26 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction { checkAndProceedStage(); } + private void handleReportPowerStatus(HdmiCecMessage cmd) { + Preconditions.checkState(mProcessedDeviceCount < mDevices.size()); + + DeviceInfo current = mDevices.get(mProcessedDeviceCount); + if (current.mLogicalAddress != cmd.getSource()) { + Slog.w(TAG, "Unmatched address[expected:" + current.mLogicalAddress + ", actual:" + + cmd.getSource()); + return; + } + + if (cmd.getOpcode() != Constants.MESSAGE_FEATURE_ABORT) { + byte[] params = cmd.getParams(); + int powerStatus = params[0] & 0xFF; + current.mPowerStatus = powerStatus; + } + + increaseProcessedDeviceCount(); + checkAndProceedStage(); + } + private void increaseProcessedDeviceCount() { mProcessedDeviceCount++; mTimeoutRetry = 0; @@ -402,6 +459,9 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction { startVendorIdStage(); return; case STATE_WAITING_FOR_VENDOR_ID: + startPowerStatusStage(); + return; + case STATE_WAITING_FOR_POWER: wrapUpAndFinish(); return; default: @@ -427,6 +487,9 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction { case STATE_WAITING_FOR_VENDOR_ID: queryVendorId(address); return; + case STATE_WAITING_FOR_POWER: + queryPowerStatus(address); + return; default: return; } @@ -448,7 +511,11 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction { } mTimeoutRetry = 0; Slog.v(TAG, "Timeout[State=" + mState + ", Processed=" + mProcessedDeviceCount); - removeDevice(mProcessedDeviceCount); + if (mState != STATE_WAITING_FOR_POWER) { + removeDevice(mProcessedDeviceCount); + } else { + increaseProcessedDeviceCount(); + } checkAndProceedStage(); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index c9eef0f5fbb76..1029a0d7677d1 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -1087,6 +1087,10 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { @ServiceThreadOnly private void launchDeviceDiscovery() { assertRunOnServiceThread(); + if (hasAction(DeviceDiscoveryAction.class)) { + Slog.i(TAG, "Device Discovery Action is in progress. Restarting."); + removeAction(DeviceDiscoveryAction.class); + } DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, new DeviceDiscoveryCallback() { @Override