From ed0864557b3340ab7db00e2dc95b29c4b8bb485d Mon Sep 17 00:00:00 2001 From: Jinsuk Kim Date: Mon, 18 Aug 2014 15:01:53 +0900 Subject: [PATCH] CEC: Invoke events listener upon MHL device state change With this change, mobile devices state changes are propagated through TIF to UI, hence the input pickers shows the mobile devices as expected. Bug: 16986744 Change-Id: Id633207acf4f814f57d43cc1de5f8cb88ac23ad6 --- .../android/hardware/hdmi/HdmiDeviceInfo.java | 2 +- .../server/hdmi/HdmiCecLocalDeviceTv.java | 6 +- .../server/hdmi/HdmiControlService.java | 58 ++++++++++++++++--- .../com/android/server/hdmi/HdmiUtils.java | 16 +++++ 4 files changed, 68 insertions(+), 14 deletions(-) diff --git a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java index 97da3a2f16b09..d8da80e667326 100644 --- a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java +++ b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java @@ -230,7 +230,7 @@ public class HdmiDeviceInfo implements Parcelable { mDeviceType = DEVICE_RESERVED; mVendorId = 0; mDevicePowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN; - mDisplayName = "MHL"; + mDisplayName = "Mobile"; mDeviceId = adopterId; mAdopterId = deviceId; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 809fef42875c8..126a56d5915af 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -1007,10 +1007,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { /** * Return external input devices. */ - List getSafeExternalInputs() { - synchronized (mLock) { - return mSafeExternalInputs; - } + List getSafeExternalInputsLocked() { + return mSafeExternalInputs; } @ServiceThreadOnly diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 14c066ebc305c..0b2cf8a74332e 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -16,6 +16,8 @@ package com.android.server.hdmi; +import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE; +import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE; import static com.android.server.hdmi.Constants.DISABLED; import static com.android.server.hdmi.Constants.ENABLED; import static com.android.server.hdmi.Constants.OPTION_CEC_AUTO_WAKEUP; @@ -202,6 +204,9 @@ public final class HdmiControlService extends SystemService { @GuardedBy("mLock") private boolean mMhlInputChangeEnabled; + @GuardedBy("mLock") + private List mMhlDevices; + // List of listeners registered by callers that want to get notified of // system audio mode changes. private final ArrayList @@ -293,6 +298,7 @@ public final class HdmiControlService extends SystemService { Slog.i(TAG, "Device does not support MHL-control."); } initPortInfo(); + mMhlDevices = Collections.emptyList(); mMessageValidator = new HdmiCecMessageValidator(this); publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); @@ -684,16 +690,16 @@ public final class HdmiControlService extends SystemService { /** * Called when a new hotplug event is issued. * - * @param portNo hdmi port number where hot plug event issued. + * @param portId hdmi port number where hot plug event issued. * @param connected whether to be plugged in or not */ @ServiceThreadOnly - void onHotplug(int portNo, boolean connected) { + void onHotplug(int portId, boolean connected) { assertRunOnServiceThread(); for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { - device.onHotplug(portNo, connected); + device.onHotplug(portId, connected); } - announceHotplugEvent(portNo, connected); + announceHotplugEvent(portId, connected); } /** @@ -794,10 +800,15 @@ public final class HdmiControlService extends SystemService { HdmiMhlLocalDevice device = mMhlController.removeLocalDevice(portId); if (device != null) { device.onDeviceRemoved(); + // There is no explicit event for device removal unlike capability register event + // used for device addition . Hence we remove the device on hotplug event. + invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE); + updateSafeMhlInput(); } else { Slog.w(TAG, "No device to remove:[portId=" + portId); } } + announceHotplugEvent(portId, connected); } @ServiceThreadOnly @@ -824,18 +835,45 @@ public final class HdmiControlService extends SystemService { } @ServiceThreadOnly - void handleCapabilityRegisterChanged(int portId, int adopterId, int deviceId) { + void handleMhlCapabilityRegisterChanged(int portId, int adopterId, int deviceId) { assertRunOnServiceThread(); HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); - // Hot plug event should be called before capability register change event. + + // Hotplug event should already have been called before capability register change event. if (device != null) { device.setCapabilityRegister(adopterId, deviceId); + invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_ADD_DEVICE); + updateSafeMhlInput(); } else { Slog.w(TAG, "No mhl device exists for capability register change event[portId:" + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]"); } } + @ServiceThreadOnly + private void updateSafeMhlInput() { + assertRunOnServiceThread(); + List inputs = Collections.emptyList(); + SparseArray devices = mMhlController.getAllLocalDevices(); + for (int i = 0; i < devices.size(); ++i) { + HdmiMhlLocalDevice device = devices.valueAt(i); + HdmiDeviceInfo info = device.getInfo(); + if (info != null) { + if (inputs.isEmpty()) { + inputs = new ArrayList<>(); + } + inputs.add(device.getInfo()); + } + } + synchronized (mLock) { + mMhlDevices = inputs; + } + } + + private List getMhlDevicesLocked() { + return mMhlDevices; + } + // Record class that monitors the event of the caller of being killed. Used to clean up // the listener list and record list accordingly. private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { @@ -1139,10 +1177,12 @@ public final class HdmiControlService extends SystemService { // No need to hold the lock for obtaining TV device as the local device instance // is preserved while the HDMI control is enabled. HdmiCecLocalDeviceTv tv = tv(); - if (tv == null) { - return Collections.emptyList(); + synchronized (mLock) { + List cecDevices = (tv == null) + ? Collections.emptyList() + : tv.getSafeExternalInputsLocked(); + return HdmiUtils.mergeToUnmodifiableList(cecDevices, getMhlDevicesLocked()); } - return tv.getSafeExternalInputs(); } @Override diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java index 23f19ff5944b1..22a519bdd067a 100644 --- a/services/core/java/com/android/server/hdmi/HdmiUtils.java +++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java @@ -206,6 +206,22 @@ final class HdmiUtils { return list; } + static List mergeToUnmodifiableList(List a, List b) { + if (a.isEmpty() && b.isEmpty()) { + return Collections.emptyList(); + } + if (a.isEmpty()) { + return Collections.unmodifiableList(b); + } + if (b.isEmpty()) { + return Collections.unmodifiableList(a); + } + List newList = new ArrayList<>(); + newList.addAll(a); + newList.addAll(b); + return Collections.unmodifiableList(newList); + } + /** * See if the new path is affecting the active path. *