diff options
5 files changed, 146 insertions, 158 deletions
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java index 5141d16a2a70..f329c6907eca 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecController.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java @@ -47,6 +47,21 @@ import java.util.List; final class HdmiCecController { private static final String TAG = "HdmiCecController"; + /** + * Interface to report allocated logical address. + */ + interface AllocateAddressCallback { + /** + * Called when a new logical address is allocated. + * + * @param deviceType requested device type to allocate logical address + * @param logicalAddress allocated logical address. If it is + * {@link HdmiCec#ADDR_UNREGISTERED}, it means that + * it failed to allocate logical address for the given device type + */ + void onAllocated(int deviceType, int logicalAddress); + } + private static final byte[] EMPTY_BODY = EmptyArray.BYTE; // A message to pass cec send command to IO looper. @@ -116,45 +131,13 @@ final class HdmiCecController { mNativePtr = nativePtr; } - /** - * Perform initialization for each hosted device. - * - * @param deviceTypes array of device types - */ - void initializeLocalDevices(int[] deviceTypes, - HdmiCecLocalDevice.AddressAllocationCallback callback) { - assertRunOnServiceThread(); - for (int type : deviceTypes) { - HdmiCecLocalDevice device = HdmiCecLocalDevice.create(this, type, callback); - if (device == null) { - continue; - } - // TODO: Consider restoring the local device addresses from persistent storage - // to allocate the same addresses again if possible. - device.setPreferredAddress(HdmiCec.ADDR_UNREGISTERED); - mLocalDevices.put(type, device); - device.init(); - } - } - - /** - * Interface to report allocated logical address. - */ - interface AllocateLogicalAddressCallback { - /** - * Called when a new logical address is allocated. - * - * @param deviceType requested device type to allocate logical address - * @param logicalAddress allocated logical address. If it is - * {@link HdmiCec#ADDR_UNREGISTERED}, it means that - * it failed to allocate logical address for the given device type - */ - void onAllocated(int deviceType, int logicalAddress); + void addLocalDevice(int deviceType, HdmiCecLocalDevice device) { + mLocalDevices.put(deviceType, device); } /** * Allocate a new logical address of the given device type. Allocated - * address will be reported through {@link AllocateLogicalAddressCallback}. + * address will be reported through {@link AllocateAddressCallback}. * * <p> Declared as package-private, accessed by {@link HdmiControlService} only. * @@ -166,7 +149,7 @@ final class HdmiCecController { * @param callback callback interface to report allocated logical address to caller */ void allocateLogicalAddress(final int deviceType, final int preferredAddress, - final AllocateLogicalAddressCallback callback) { + final AllocateAddressCallback callback) { assertRunOnServiceThread(); runOnIoThread(new Runnable() { @@ -178,7 +161,7 @@ final class HdmiCecController { } private void handleAllocateLogicalAddress(final int deviceType, int preferredAddress, - final AllocateLogicalAddressCallback callback) { + final AllocateAddressCallback callback) { assertRunOnIoThread(); int startAddress = preferredAddress; // If preferred address is "unregistered", start address will be the smallest diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index aac2a1544b08..23454ad7ad3d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -16,8 +16,6 @@ package com.android.server.hdmi; -import com.android.server.hdmi.HdmiCecController.AllocateLogicalAddressCallback; - import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecDeviceInfo; @@ -27,84 +25,43 @@ import android.hardware.hdmi.HdmiCecDeviceInfo; */ abstract class HdmiCecLocalDevice { - protected final HdmiCecController mController; + protected final HdmiControlService mService; protected final int mDeviceType; - protected final AddressAllocationCallback mAllocationCallback; protected int mAddress; protected int mPreferredAddress; protected HdmiCecDeviceInfo mDeviceInfo; - /** - * Callback interface to notify newly allocated logical address of the given - * local device. - */ - interface AddressAllocationCallback { - /** - * Called when a logical address of the given device is allocated. - * - * @param deviceType original device type - * @param logicalAddress newly allocated logical address - */ - void onAddressAllocated(int deviceType, int logicalAddress); - } - - protected HdmiCecLocalDevice(HdmiCecController controller, int deviceType, - AddressAllocationCallback callback) { - mController = controller; + protected HdmiCecLocalDevice(HdmiControlService service, int deviceType) { + mService = service; mDeviceType = deviceType; - mAllocationCallback = callback; mAddress = HdmiCec.ADDR_UNREGISTERED; } // Factory method that returns HdmiCecLocalDevice of corresponding type. - static HdmiCecLocalDevice create(HdmiCecController controller, int deviceType, - AddressAllocationCallback callback) { + static HdmiCecLocalDevice create(HdmiControlService service, int deviceType) { switch (deviceType) { case HdmiCec.DEVICE_TV: - return new HdmiCecLocalDeviceTv(controller, callback); + return new HdmiCecLocalDeviceTv(service); case HdmiCec.DEVICE_PLAYBACK: - return new HdmiCecLocalDevicePlayback(controller, callback); + return new HdmiCecLocalDevicePlayback(service); default: return null; } } - abstract void init(); + void init() { + mPreferredAddress = HdmiCec.ADDR_UNREGISTERED; + // TODO: load preferred address from permanent storage. + } /** - * Called when a logical address of the local device is allocated. - * Note that internal variables are updated before it's called. + * Called once a logical address of the local device is allocated. */ protected abstract void onAddressAllocated(int logicalAddress); - protected void allocateAddress(int type) { - mController.allocateLogicalAddress(type, mPreferredAddress, - new AllocateLogicalAddressCallback() { - @Override - public void onAllocated(int deviceType, int logicalAddress) { - mAddress = mPreferredAddress = logicalAddress; - - // Create and set device info. - HdmiCecDeviceInfo deviceInfo = createDeviceInfo(mAddress, deviceType); - setDeviceInfo(deviceInfo); - mController.addDeviceInfo(deviceInfo); - - mController.addLogicalAddress(logicalAddress); - onAddressAllocated(logicalAddress); - if (mAllocationCallback != null) { - mAllocationCallback.onAddressAllocated(deviceType, logicalAddress); - } - } - }); - } - - private final HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { - int vendorId = mController.getVendorId(); - int physicalAddress = mController.getPhysicalAddress(); - // TODO: get device name read from system configuration. - String displayName = HdmiCec.getDefaultDeviceName(logicalAddress); - return new HdmiCecDeviceInfo(logicalAddress, - physicalAddress, deviceType, vendorId, displayName); + final void handleAddressAllocated(int logicalAddress) { + mAddress = mPreferredAddress = logicalAddress; + onAddressAllocated(logicalAddress); } HdmiCecDeviceInfo getDeviceInfo() { @@ -128,4 +85,8 @@ abstract class HdmiCecLocalDevice { void setPreferredAddress(int addr) { mPreferredAddress = addr; } + + int getPreferredAddress() { + return mPreferredAddress; + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java index 3347725098ab..d79e283b3c85 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java @@ -23,18 +23,13 @@ import android.hardware.hdmi.HdmiCec; */ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { - HdmiCecLocalDevicePlayback(HdmiCecController controller, AddressAllocationCallback callback) { - super(controller, HdmiCec.DEVICE_PLAYBACK, callback); - } - - @Override - void init() { - allocateAddress(mDeviceType); + HdmiCecLocalDevicePlayback(HdmiControlService service) { + super(service, HdmiCec.DEVICE_PLAYBACK); } @Override protected void onAddressAllocated(int logicalAddress) { - mController.sendCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( - mAddress, mController.getPhysicalAddress(), mDeviceType)); + mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + mAddress, mService.getPhysicalAddress(), mDeviceType)); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 93761abab6d0..72d7f2d423ee 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -23,24 +23,20 @@ import android.hardware.hdmi.HdmiCec; */ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { - HdmiCecLocalDeviceTv(HdmiCecController controller, AddressAllocationCallback callback) { - super(controller, HdmiCec.DEVICE_TV, callback); - } - - @Override - void init() { - allocateAddress(mDeviceType); + HdmiCecLocalDeviceTv(HdmiControlService service) { + super(service, HdmiCec.DEVICE_TV); } @Override protected void onAddressAllocated(int logicalAddress) { // TODO: vendor-specific initialization here. - mController.sendCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( - mAddress, mController.getPhysicalAddress(), mDeviceType)); - mController.sendCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand( - mAddress, mController.getVendorId())); + mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + mAddress, mService.getPhysicalAddress(), mDeviceType)); + mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand( + mAddress, mService.getVendorId())); + mService.launchDeviceDiscovery(mAddress); // TODO: Start routing control action, device discovery action. } } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 0f3fc215aef7..17e0f384b2f8 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -30,12 +30,13 @@ import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.util.Slog; +import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.server.SystemService; import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback; -import com.android.server.hdmi.HdmiCecLocalDevice.AddressAllocationCallback; +import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; import java.util.ArrayList; import java.util.Iterator; @@ -134,23 +135,9 @@ public final class HdmiControlService extends SystemService { public void onStart() { mIoThread.start(); mCecController = HdmiCecController.create(this); - if (mCecController != null) { - mCecController.initializeLocalDevices(mLocalDevices, new AddressAllocationCallback() { - private final SparseIntArray mAllocated = new SparseIntArray(); - @Override - public void onAddressAllocated(int deviceType, int logicalAddress) { - mAllocated.append(deviceType, logicalAddress); - // TODO: get HdmiLCecLocalDevice and call onAddressAllocated here. - - // Once all logical allocation is done, launch device discovery - // action if one of local device is TV. - int tvAddress = mAllocated.get(HdmiCec.DEVICE_TV, -1); - if (mLocalDevices.length == mAllocated.size() && tvAddress != -1) { - launchDeviceDiscovery(tvAddress); - } - } - }); + if (mCecController != null) { + initializeLocalDevices(mLocalDevices); } else { Slog.i(TAG, "Device does not support HDMI-CEC."); } @@ -166,6 +153,46 @@ public final class HdmiControlService extends SystemService { // start to monitor the preference value and invoke SystemAudioActionFromTv if needed. } + private void initializeLocalDevices(final int[] deviceTypes) { + // A container for [Logical Address, Local device info]. + final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); + final SparseIntArray finished = new SparseIntArray(); + for (int type : deviceTypes) { + final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); + localDevice.init(); + mCecController.allocateLogicalAddress(type, + localDevice.getPreferredAddress(), new AllocateAddressCallback() { + @Override + public void onAllocated(int deviceType, int logicalAddress) { + if (logicalAddress == HdmiCec.ADDR_UNREGISTERED) { + Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); + } else { + HdmiCecDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType); + localDevice.setDeviceInfo(deviceInfo); + mCecController.addLocalDevice(deviceType, localDevice); + mCecController.addLogicalAddress(logicalAddress); + devices.append(logicalAddress, localDevice); + } + finished.append(deviceType, logicalAddress); + + // Once finish address allocation for all devices, notify + // it to each device. + if (deviceTypes.length == finished.size()) { + notifyAddressAllocated(devices); + } + } + }); + } + } + + private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices) { + for (int i = 0; i < devices.size(); ++i) { + int address = devices.keyAt(i); + HdmiCecLocalDevice device = devices.valueAt(i); + device.onAddressAllocated(address); + } + } + /** * Returns {@link Looper} for IO operation. * @@ -186,6 +213,20 @@ public final class HdmiControlService extends SystemService { } /** + * Returns physical address of the device. + */ + int getPhysicalAddress() { + return mCecController.getPhysicalAddress(); + } + + /** + * Returns vendor id of CEC service. + */ + int getVendorId() { + return mCecController.getVendorId(); + } + + /** * Add and start a new {@link FeatureAction} to the action queue. * * @param action {@link FeatureAction} to add and start @@ -352,6 +393,45 @@ public final class HdmiControlService extends SystemService { mCecController.pollDevices(callback, retryCount); } + + /** + * Launch device discovery sequence. It starts with clearing the existing device info list. + * Note that it assumes that logical address of all local devices is already allocated. + * + * @param sourceAddress a logical address of tv + */ + void launchDeviceDiscovery(int sourceAddress) { + // At first, clear all existing device infos. + mCecController.clearDeviceInfoList(); + + // TODO: check whether TV is one of local devices. + DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, sourceAddress, + new DeviceDiscoveryCallback() { + @Override + public void onDeviceDiscoveryDone(List<HdmiCecDeviceInfo> deviceInfos) { + for (HdmiCecDeviceInfo info : deviceInfos) { + mCecController.addDeviceInfo(info); + } + + // Add device info of all local devices. + for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { + mCecController.addDeviceInfo(device.getDeviceInfo()); + } + + // TODO: start hot-plug detection sequence here. + // addAndStartAction(new HotplugDetectionAction()); + } + }); + addAndStartAction(action); + } + + private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { + // TODO: get device name read from system configuration. + String displayName = HdmiCec.getDefaultDeviceName(logicalAddress); + return new HdmiCecDeviceInfo(logicalAddress, + getPhysicalAddress(), deviceType, getVendorId(), displayName); + } + private void handleReportPhysicalAddress(HdmiCecMessage message) { // At first, try to consume it. if (dispatchMessageToAction(message)) { @@ -505,33 +585,6 @@ public final class HdmiControlService extends SystemService { mCecController.addDeviceInfo(info); } - // Launch device discovery sequence. - // It starts with clearing the existing device info list. - // Note that it assumes that logical address of all local devices is already allocated. - private void launchDeviceDiscovery(int sourceAddress) { - // At first, clear all existing device infos. - mCecController.clearDeviceInfoList(); - - // TODO: check whether TV is one of local devices. - DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, sourceAddress, - new DeviceDiscoveryCallback() { - @Override - public void onDeviceDiscoveryDone(List<HdmiCecDeviceInfo> deviceInfos) { - for (HdmiCecDeviceInfo info : deviceInfos) { - mCecController.addDeviceInfo(info); - } - - // Add device info of all local devices. - for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { - mCecController.addDeviceInfo(device.getDeviceInfo()); - } - - // TODO: start hot-plug detection sequence here. - // addAndStartAction(new HotplugDetectionAction()); - } - }); - addAndStartAction(action); - } private void enforceAccessPermission() { getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); |