OSDN Git Service

Refactor HdmiCecLocalDevice and logical address allocation logic.
authorJungshik Jang <jayjang@google.com>
Tue, 3 Jun 2014 07:22:30 +0000 (16:22 +0900)
committerJungshik Jang <jayjang@google.com>
Thu, 5 Jun 2014 01:19:05 +0000 (10:19 +0900)
1. Factor out logical allocation logic to HdmiControlService.
2. Contains a reference to HdmiControlService rather than
  HdmiCecController so that it enables to access service's logic
  directly.
3. Move launch device discovery logic to HdmiCecLocalDeviceTv.

Change-Id: Ic97b4d51311a3c18f6d586c2245cac410cbd370e

services/core/java/com/android/server/hdmi/HdmiCecController.java
services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
services/core/java/com/android/server/hdmi/HdmiControlService.java

index 5141d16..f329c69 100644 (file)
@@ -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
index aac2a15..23454ad 100644 (file)
@@ -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;
+    }
 }
index 3347725..d79e283 100644 (file)
@@ -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));
     }
 }
index 93761ab..72d7f2d 100644 (file)
@@ -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.
     }
 }
index 0f3fc21..17e0f38 100644 (file)
@@ -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);