Hook up native mhl api to HdmiControl Service.

This change hooks up all apis defined in mhl hal to
java layer's HdmiMhlController and HdmiControlService.
Along with HdmiMhlController, this change includes followings.

1. HdmiMhlLocalDevice
A logical container for a mhl device connected to specific hdmi port

2. HdmiMhlFeatureAction
A base feature action class for mhl's state behaviors like RAP and RCP.

Bug: 16215362

Change-Id: If177999853f60b68bd079549660a3f4982cb9d9e
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 0003210..b55cf62 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -244,5 +244,26 @@
     static final int DISABLED = 0;
     static final int ENABLED = 1;
 
+    // --------------------------------------------------
+    // MHL sub command message types.
+    static final int MHL_MSG_MSGE  = 0x02;
+    static final int MHL_MSG_RCP   = 0x10;
+    static final int MHL_MSG_RCPK  = 0x11;
+    static final int MHL_MSG_RCPE  = 0x12;
+    static final int MHL_MSG_RAP   = 0x20;
+    static final int MHL_MSG_RAPK  = 0x21;
+
+    // MHL RAP messages.
+    static final int MHL_RAP_ACTION_POLL = 0x00;
+    static final int MHL_RAP_ACTION_CONTENT_ON = 0x10;
+    static final int MHL_RAP_ACTION_CONTENT_OFF = 0x11;
+
+    static final int MHL_INVALID_ADOPTER_ID = -1;
+    static final int MHL_INVALID_DEVICE_ID = -1;
+
+    static final int MHL_CBUS_MODE_OCBUS = 1;
+    static final int MHL_CBUS_MODE_ECBUS_S = 2;
+    static final int MHL_CBUS_MODE_ECBUS_D = 3;
+
     private Constants() { /* cannot be instantiated */ }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 10e4b6e..cf06ca8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -94,13 +94,14 @@
     // interacts with HAL.
     private volatile long mNativePtr;
 
-    private HdmiControlService mService;
+    private final HdmiControlService mService;
 
     // Stores the local CEC devices in the system. Device type is used for key.
     private final SparseArray<HdmiCecLocalDevice> mLocalDevices = new SparseArray<>();
 
     // Private constructor.  Use HdmiCecController.create().
-    private HdmiCecController() {
+    private HdmiCecController(HdmiControlService service) {
+        mService = service;
     }
 
     /**
@@ -114,21 +115,20 @@
      *         returns {@code null}.
      */
     static HdmiCecController create(HdmiControlService service) {
-        HdmiCecController controller = new HdmiCecController();
+        HdmiCecController controller = new HdmiCecController(service);
         long nativePtr = nativeInit(controller, service.getServiceLooper().getQueue());
         if (nativePtr == 0L) {
             controller = null;
             return null;
         }
 
-        controller.init(service, nativePtr);
+        controller.init(nativePtr);
         return controller;
     }
 
-    private void init(HdmiControlService service, long nativePtr) {
-        mService = service;
-        mIoHandler = new Handler(service.getServiceLooper());
-        mControlHandler = new Handler(service.getServiceLooper());
+    private void init(long nativePtr) {
+        mIoHandler = new Handler(mService.getServiceLooper());
+        mControlHandler = new Handler(mService.getServiceLooper());
         mNativePtr = nativePtr;
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
index f32e660..26d2cde 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
@@ -28,9 +28,9 @@
 import java.util.List;
 
 /**
- * Encapsulates a sequence of CEC/MHL command exchange for a certain feature.
+ * Encapsulates a sequence of CEC command exchange for a certain feature.
  * <p>
- * Many CEC/MHL features are accomplished by CEC devices on the bus exchanging more than one
+ * Many CEC features are accomplished by CEC devices on the bus exchanging more than one
  * command. {@link HdmiCecFeatureAction} represents the life cycle of the communication, manages the
  * state as the process progresses, and if necessary, returns the result to the caller which
  * initiates the action, through the callback given at the creation of the object. All the actual
@@ -42,7 +42,7 @@
  * package private, accessed by {@link HdmiControlService} only.
  */
 abstract class HdmiCecFeatureAction {
-    private static final String TAG = "FeatureAction";
+    private static final String TAG = "HdmiCecFeatureAction";
 
     // Timer handler message used for timeout event
     protected static final int MSG_TIMEOUT = 100;
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 356db66..9a8ef3a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -604,6 +604,18 @@
         sendCecCommand(command, null);
     }
 
+    @ServiceThreadOnly
+    void sendMhlSubcommand(int portId, HdmiMhlSubcommand command) {
+        assertRunOnServiceThread();
+        sendMhlSubcommand(portId, command, null);
+    }
+
+    @ServiceThreadOnly
+    void sendMhlSubcommand(int portId, HdmiMhlSubcommand command, SendMessageCallback callback) {
+        assertRunOnServiceThread();
+        mMhlController.sendSubcommand(portId, command, callback);
+    }
+
     /**
      * Send <Feature Abort> command on the given CEC message if possible.
      * If the aborted message is invalid, then it wont send the message.
@@ -732,6 +744,74 @@
                 getVendorId(), displayName);
     }
 
+    @ServiceThreadOnly
+    boolean handleMhlSubcommand(int portId, HdmiMhlSubcommand message) {
+        assertRunOnServiceThread();
+
+        HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId);
+        if (device != null) {
+            return device.handleSubcommand(message);
+        }
+        Slog.w(TAG, "No mhl device exists[portId:" + portId + ", message:" + message);
+        return false;
+    }
+
+    @ServiceThreadOnly
+    void handleMhlHotplugEvent(int portId, boolean connected) {
+        assertRunOnServiceThread();
+        if (connected) {
+            HdmiMhlLocalDevice newDevice = new HdmiMhlLocalDevice(this, portId);
+            HdmiMhlLocalDevice oldDevice = mMhlController.addLocalDevice(newDevice);
+            if (oldDevice != null) {
+                oldDevice.onDeviceRemoved();
+                Slog.i(TAG, "Old device of port " + portId + " is removed");
+            }
+        } else {
+            HdmiMhlLocalDevice device = mMhlController.removeLocalDevice(portId);
+            if (device != null) {
+                device.onDeviceRemoved();
+            } else {
+                Slog.w(TAG, "No device to remove:[portId=" + portId);
+            }
+        }
+    }
+
+    @ServiceThreadOnly
+    void handleMhlCbusModeChanged(int portId, int cbusmode) {
+        assertRunOnServiceThread();
+        HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId);
+        if (device != null) {
+            device.setCbusMode(cbusmode);
+        } else {
+            Slog.w(TAG, "No mhl device exists for cbus mode change[portId:" + portId +
+                    ", cbusmode:" + cbusmode + "]");
+        }
+    }
+
+    @ServiceThreadOnly
+    void handleMhlVbusOvercurrent(int portId, boolean on) {
+        assertRunOnServiceThread();
+        HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId);
+        if (device != null) {
+            device.onVbusOvercurrentDetected(on);
+        } else {
+            Slog.w(TAG, "No mhl device exists for vbus overcurrent event[portId:" + portId + "]");
+        }
+    }
+
+    @ServiceThreadOnly
+    void handleCapabilityRegisterChanged(int portId, int adopterId, int deviceId) {
+        assertRunOnServiceThread();
+        HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId);
+        // Hot plug event should be called before capability register change event.
+        if (device != null) {
+            device.setCapabilityRegister(adopterId, deviceId);
+        } else {
+            Slog.w(TAG, "No mhl device exists for capability register change event[portId:"
+                    + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]");
+        }
+    }
+
     // 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 {