tv.cec: Update framework code to call Treble HAL

Bug: 32073236
Test: Checked CEC features works on fugu after applying Treble HAL
Change-Id: I26df037594e2505bd8f2d2bb6222cba5ddca2906
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 11586ee..88a8385 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -19,8 +19,9 @@
 LOCAL_JAVA_LIBRARIES := \
     services.net \
     telephony-common \
+    android.hardware.light@2.0-java \
     android.hardware.power@1.0-java \
-    android.hardware.light@2.0-java
+    android.hardware.tv.cec@1.0-java
 
 LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
 
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 603402e..a2a55e532 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -188,12 +188,6 @@
     static final int INVALID_PHYSICAL_ADDRESS = HdmiDeviceInfo.PATH_INVALID;
     static final int PATH_INTERNAL = HdmiDeviceInfo.PATH_INTERNAL;
 
-    // Send result codes. It should be consistent with hdmi_cec.h's send_message error code.
-    static final int SEND_RESULT_SUCCESS = 0;
-    static final int SEND_RESULT_NAK = 1;
-    static final int SEND_RESULT_BUSY = 2;
-    static final int SEND_RESULT_FAILURE = 3;
-
     // Strategy for device polling.
     // Should use "OR(|) operation of POLL_STRATEGY_XXX and POLL_ITERATION_XXX.
     static final int POLL_STRATEGY_MASK = 0x3;  // first and second bit.
@@ -231,26 +225,7 @@
     static final int RECORDING_TYPE_OWN_SOURCE = 4;
 
     // Definitions used for setOption(). These should be in sync with the definition
-    // in hardware/libhardware/include/hardware/{hdmi_cec.h,mhl.h}.
-
-    // TV gets turned on by incoming <Text/Image View On>. enabled by default.
-    // If set to disabled, TV won't turn on automatically.
-    static final int OPTION_CEC_AUTO_WAKEUP = 1;
-
-    // If set to disabled, all CEC commands are discarded.
-    static final int OPTION_CEC_ENABLE = 2;
-
-    // If set to disabled, system service yields control of CEC to sub-microcontroller.
-    // If enabled, it takes the control back.
-    static final int OPTION_CEC_SERVICE_CONTROL = 3;
-
-    // Put other devices to standby when TV goes to standby. enabled by default.
-    // If set to disabled, TV doesn't send <Standby> to other devices.
-    static final int OPTION_CEC_AUTO_DEVICE_OFF = 4;
-
-    // Passes the language used in the system when updated. The value to use is the 3 byte
-    // code as defined in ISO/FDIS 639-2.
-    static final int OPTION_CEC_SET_LANGUAGE = 5;
+    // in hardware/libhardware/include/hardware/mhl.h.
 
     // If set to disabled, TV does not switch ports when mobile device is connected.
     static final int OPTION_MHL_INPUT_SWITCHING = 101;
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
index 5a1d896..c684a56 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -16,13 +16,13 @@
 
 package com.android.server.hdmi;
 
-import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiTvClient;
 import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.RemoteException;
 import android.util.Slog;
-
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 
 /**
@@ -95,7 +95,7 @@
         sendCommand(mGivePowerStatus, new SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     invokeCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED);
                     finish();
                     return;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 687aaa1..461a9b0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -17,23 +17,23 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.tv.cec.V1_0.Result;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.util.Slog;
 import android.util.SparseArray;
-
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Predicate;
 import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
-
-import libcore.util.EmptyArray;
-
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
+import libcore.util.EmptyArray;
+import sun.util.locale.LanguageTag;
 
 /**
  * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command
@@ -256,7 +256,7 @@
         if (HdmiUtils.isValidAddress(newLogicalAddress)) {
             return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
         } else {
-            return -1;
+            return Result.FAILURE_INVALID_ARGS;
         }
     }
 
@@ -320,13 +320,27 @@
      * Set an option to CEC HAL.
      *
      * @param flag key of option
-     * @param value value of option
+     * @param enabled whether to enable/disable the given option.
      */
     @ServiceThreadOnly
-    void setOption(int flag, int value) {
+    void setOption(int flag, boolean enabled) {
         assertRunOnServiceThread();
-        HdmiLogger.debug("setOption: [flag:%d, value:%d]", flag, value);
-        nativeSetOption(mNativePtr, flag, value);
+        HdmiLogger.debug("setOption: [flag:%d, enabled:%b]", flag, enabled);
+        nativeSetOption(mNativePtr, flag, enabled);
+    }
+
+    /**
+     * Informs CEC HAL about the current system language.
+     *
+     * @param language Three-letter code defined in ISO/FDIS 639-2. Must be lowercase letters.
+     */
+    @ServiceThreadOnly
+    void setLanguage(String language) {
+        assertRunOnServiceThread();
+        if (!LanguageTag.isLanguage(language)) {
+            return;
+        }
+        nativeSetLanguage(mNativePtr, language);
     }
 
     /**
@@ -336,9 +350,9 @@
      * @param enabled whether to enable/disable ARC
      */
     @ServiceThreadOnly
-    void setAudioReturnChannel(int port, boolean enabled) {
+    void enableAudioReturnChannel(int port, boolean enabled) {
         assertRunOnServiceThread();
-        nativeSetAudioReturnChannel(mNativePtr, port, enabled);
+        nativeEnableAudioReturnChannel(mNativePtr, port, enabled);
     }
 
     /**
@@ -472,9 +486,9 @@
             // <Polling Message> is a message which has empty body.
             int ret =
                     nativeSendCecCommand(mNativePtr, sourceAddress, destinationAddress, EMPTY_BODY);
-            if (ret == Constants.SEND_RESULT_SUCCESS) {
+            if (ret == SendMessageResult.SUCCESS) {
                 return true;
-            } else if (ret != Constants.SEND_RESULT_NAK) {
+            } else if (ret != SendMessageResult.NACK) {
                 // Unusual failure
                 HdmiLogger.warning("Failed to send a polling message(%d->%d) with return code %d",
                         sourceAddress, destinationAddress, ret);
@@ -572,17 +586,17 @@
                 HdmiLogger.debug("[S]:" + cecMessage);
                 byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
                 int i = 0;
-                int errorCode = Constants.SEND_RESULT_SUCCESS;
+                int errorCode = SendMessageResult.SUCCESS;
                 do {
                     errorCode = nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
                             cecMessage.getDestination(), body);
-                    if (errorCode == Constants.SEND_RESULT_SUCCESS) {
+                    if (errorCode == SendMessageResult.SUCCESS) {
                         break;
                     }
                 } while (i++ < HdmiConfig.RETRANSMISSION_COUNT);
 
                 final int finalError = errorCode;
-                if (finalError != Constants.SEND_RESULT_SUCCESS) {
+                if (finalError != SendMessageResult.SUCCESS) {
                     Slog.w(TAG, "Failed to send " + cecMessage);
                 }
                 if (callback != null) {
@@ -636,7 +650,8 @@
     private static native int nativeGetVersion(long controllerPtr);
     private static native int nativeGetVendorId(long controllerPtr);
     private static native HdmiPortInfo[] nativeGetPortInfos(long controllerPtr);
-    private static native void nativeSetOption(long controllerPtr, int flag, int value);
-    private static native void nativeSetAudioReturnChannel(long controllerPtr, int port, boolean flag);
+    private static native void nativeSetOption(long controllerPtr, int flag, boolean enabled);
+    private static native void nativeSetLanguage(long controllerPtr, String language);
+    private static native void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag);
     private static native boolean nativeIsConnected(long controllerPtr, int port);
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 43d8bac..c85d979 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -36,6 +36,7 @@
 import android.hardware.hdmi.HdmiRecordSources;
 import android.hardware.hdmi.HdmiTimerRecordSources;
 import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.tv.TvInputInfo;
@@ -46,7 +47,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
-
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
@@ -57,9 +57,9 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
-import java.util.HashMap;
 
 /**
  * Represent a logical device of type TV residing in Android system.
@@ -910,7 +910,7 @@
         HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled);
         boolean oldStatus = mArcEstablished;
         // 1. Enable/disable ARC circuit.
-        setAudioReturnChannel(enabled);
+        enableAudioReturnChannel(enabled);
         // 2. Notify arc status to audio service.
         notifyArcStatusToAudioService(enabled);
         // 3. Update arc status;
@@ -922,11 +922,11 @@
      * Switch hardware ARC circuit in the system.
      */
     @ServiceThreadOnly
-    void setAudioReturnChannel(boolean enabled) {
+    void enableAudioReturnChannel(boolean enabled) {
         assertRunOnServiceThread();
         HdmiDeviceInfo avr = getAvrDeviceInfo();
         if (avr != null) {
-            mService.setAudioReturnChannel(avr.getPortId(), enabled);
+            mService.enableAudioReturnChannel(avr.getPortId(), enabled);
         }
     }
 
@@ -1870,7 +1870,7 @@
         mService.sendCecCommand(message, new SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     announceClearTimerRecordingResult(recorderAddress,
                             CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE);
                 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 72ee218..18f1b6c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -20,10 +20,6 @@
 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;
-import static com.android.server.hdmi.Constants.OPTION_CEC_ENABLE;
-import static com.android.server.hdmi.Constants.OPTION_CEC_SERVICE_CONTROL;
-import static com.android.server.hdmi.Constants.OPTION_CEC_SET_LANGUAGE;
 import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE;
 import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING;
 import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE;
@@ -49,6 +45,8 @@
 import android.hardware.hdmi.IHdmiRecordListener;
 import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
 import android.hardware.hdmi.IHdmiVendorCommandListener;
+import android.hardware.tv.cec.V1_0.OptionKey;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.media.AudioManager;
 import android.media.tv.TvInputManager;
 import android.media.tv.TvInputManager.TvInputCallback;
@@ -69,7 +67,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
-
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.SystemService;
@@ -77,11 +74,6 @@
 import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
 import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
 import com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback;
-import com.android.server.hdmi.SelectRequestBuffer.DeviceSelectRequest;
-import com.android.server.hdmi.SelectRequestBuffer.PortSelectRequest;
-
-import libcore.util.EmptyArray;
-
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -89,6 +81,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import libcore.util.EmptyArray;
 
 /**
  * Provides a service for sending and processing HDMI control messages,
@@ -123,9 +116,10 @@
          *
          * @param error result of send request.
          * <ul>
-         * <li>{@link Constants#SEND_RESULT_SUCCESS}
-         * <li>{@link Constants#SEND_RESULT_NAK}
-         * <li>{@link Constants#SEND_RESULT_FAILURE}
+         * <li>{@link SendMessageResult#SUCCESS}
+         * <li>{@link SendMessageResult#NACK}
+         * <li>{@link SendMessageResult#BUSY}
+         * <li>{@link SendMessageResult#FAIL}
          * </ul>
          */
         void onSendCompleted(int error);
@@ -466,7 +460,7 @@
         mWakeUpMessageReceived = false;
 
         if (isTvDeviceEnabled()) {
-            mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup()));
+            mCecController.setOption(OptionKey.WAKEUP, tv().getAutoWakeup());
         }
         int reason = -1;
         switch (initiatedBy) {
@@ -519,7 +513,7 @@
                     if (isTvDeviceEnabled()) {
                         tv().setAutoWakeup(enabled);
                     }
-                    setCecOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled));
+                    setCecOption(OptionKey.WAKEUP, enabled);
                     break;
                 case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED:
                     for (int type : mLocalDevices) {
@@ -556,8 +550,8 @@
 
     private void initializeCec(int initiatedBy) {
         mAddressAllocated = false;
-        mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED);
-        mCecController.setOption(OPTION_CEC_SET_LANGUAGE, HdmiUtils.languageToInt(mLanguage));
+        mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
+        mCecController.setLanguage(mLanguage);
         initializeLocalDevices(initiatedBy);
     }
 
@@ -842,7 +836,7 @@
         } else {
             HdmiLogger.error("Invalid message type:" + command);
             if (callback != null) {
-                callback.onSendCompleted(Constants.SEND_RESULT_FAILURE);
+                callback.onSendCompleted(SendMessageResult.FAIL);
             }
         }
     }
@@ -884,8 +878,8 @@
         return dispatchMessageToLocalDevice(message);
     }
 
-    void setAudioReturnChannel(int portId, boolean enabled) {
-        mCecController.setAudioReturnChannel(portId, enabled);
+    void enableAudioReturnChannel(int portId, boolean enabled) {
+        mCecController.enableAudioReturnChannel(portId, enabled);
     }
 
     @ServiceThreadOnly
@@ -2079,7 +2073,7 @@
 
         if (isTvDeviceEnabled()) {
             tv().broadcastMenuLanguage(language);
-            mCecController.setOption(OPTION_CEC_SET_LANGUAGE, HdmiUtils.languageToInt(language));
+            mCecController.setLanguage(language);
         }
     }
 
@@ -2123,7 +2117,7 @@
         }
         mStandbyMessageReceived = false;
         mAddressAllocated = false;
-        mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED);
+        mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, false);
         mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, DISABLED);
     }
 
@@ -2216,7 +2210,7 @@
     }
 
     @ServiceThreadOnly
-    void setCecOption(int key, int value) {
+    void setCecOption(int key, boolean value) {
         assertRunOnServiceThread();
         mCecController.setOption(key, value);
     }
@@ -2249,7 +2243,7 @@
 
     @ServiceThreadOnly
     private void enableHdmiControlService() {
-        mCecController.setOption(OPTION_CEC_ENABLE, ENABLED);
+        mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
         mMhlController.setOption(OPTION_MHL_ENABLE, ENABLED);
 
         initializeCec(INITIATED_BY_ENABLE_CEC);
@@ -2264,7 +2258,7 @@
                 mCecController.flush(new Runnable() {
                     @Override
                     public void run() {
-                        mCecController.setOption(OPTION_CEC_ENABLE, DISABLED);
+                        mCecController.setOption(OptionKey.ENABLE_CEC, false);
                         mMhlController.setOption(OPTION_MHL_ENABLE, DISABLED);
                         clearLocalDevices();
                     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index 9aa9290..8b16411 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -291,18 +291,4 @@
                 info.getPhysicalAddress(), info.getPortId(), info.getDeviceType(),
                 info.getVendorId(), info.getDisplayName(), newPowerStatus);
     }
-
-    /**
-     * Convert 3 byte-long language code in string to integer representation.
-     * English(eng), for example, is converted to 0x656e67.
-     *
-     * @param language language code in string
-     * @return language code in integer representation
-     */
-    static int languageToInt(String language) {
-        String normalized = language.toLowerCase();
-        return ((normalized.charAt(0) & 0xFF) << 16)
-                | ((normalized.charAt(1) & 0xFF) << 8)
-                | (normalized.charAt(2) & 0xFF);
-    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index 5f2d651..e1bcd99 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -265,7 +265,7 @@
         // Turn off system audio mode and update settings.
         tv().setSystemAudioMode(false, true);
         if (tv().isArcEstablished()) {
-            tv().setAudioReturnChannel(false);
+            tv().enableAudioReturnChannel(false);
             addAndStartAction(new RequestArcTerminationAction(localDevice(), address));
         }
     }
diff --git a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
index d80b81f6..39de8ff 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
@@ -22,8 +22,8 @@
 import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE;
 import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT;
 
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.util.Slog;
-
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 
 /**
@@ -62,7 +62,7 @@
                 @Override
                     public void onSendCompleted(int error) {
                         // if failed to send <Record On>, display error message and finish action.
-                        if (error != Constants.SEND_RESULT_SUCCESS) {
+                        if (error != SendMessageResult.SUCCESS) {
                             tv().announceOneTouchRecordResult(
                                     mRecorderAddress,
                                     ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION);
diff --git a/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java b/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java
index fd7a7f9..6893012 100644
--- a/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java
+++ b/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java
@@ -18,10 +18,9 @@
 import static android.hardware.hdmi.HdmiControlManager.POWER_STATUS_UNKNOWN;
 
 import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.util.SparseIntArray;
-
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
-
 import java.util.List;
 
 /**
@@ -123,7 +122,7 @@
                         public void onSendCompleted(int error) {
                             // If fails to send <Give Device Power Status>,
                             // update power status into UNKNOWN.
-                            if (error != Constants.SEND_RESULT_SUCCESS) {
+                            if (error != SendMessageResult.SUCCESS) {
                                updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, true);
                             }
                         }
diff --git a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
index f69f975..4eb220f 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
@@ -16,6 +16,8 @@
 
 package com.android.server.hdmi;
 
+import android.hardware.tv.cec.V1_0.SendMessageResult;
+
 /**
  * Feature action that handles ARC action initiated by TV devices.
  *
@@ -44,7 +46,7 @@
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     // Turn off ARC status if <Request ARC Initiation> fails.
                     tv().setArcStatus(false);
                     finish();
diff --git a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
index f5a0115..8b5a2931 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
@@ -16,6 +16,8 @@
 
 package com.android.server.hdmi;
 
+import android.hardware.tv.cec.V1_0.SendMessageResult;
+
 /**
  * Feature action to handle <Request ARC Termination>.
  *
@@ -43,7 +45,7 @@
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     // If failed to send <Request ARC Termination>, start "Disabled" ARC
                     // transmission action.
                     disableArcTransmission();
diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
index 9b4950b..6633789 100644
--- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
+++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
@@ -17,6 +17,7 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.util.Slog;
 
 /**
@@ -81,14 +82,14 @@
             @Override
             public void onSendCompleted(int error) {
                 switch (error) {
-                    case Constants.SEND_RESULT_SUCCESS:
-                    case Constants.SEND_RESULT_BUSY:
-                    case Constants.SEND_RESULT_FAILURE:
+                    case SendMessageResult.SUCCESS:
+                    case SendMessageResult.BUSY:
+                    case SendMessageResult.FAIL:
                         // The result of the command transmission, unless it is an obvious
                         // failure indicated by the target device (or lack thereof), should
                         // not affect the ARC status. Ignores it silently.
                         break;
-                    case Constants.SEND_RESULT_NAK:
+                    case SendMessageResult.NACK:
                         // If <Report ARC Initiated> is negatively ack'ed, disable ARC and
                         // send <Report ARC Terminated> directly.
                         setArcStatus(false);
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index a209cd0..af1a85d 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -17,12 +17,12 @@
 package com.android.server.hdmi;
 
 import android.annotation.Nullable;
-import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.RemoteException;
 import android.util.Slog;
-
 import java.util.List;
 
 /**
@@ -96,7 +96,7 @@
         sendCommand(command, new HdmiControlService.SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     HdmiLogger.debug("Failed to send <System Audio Mode Request>:" + error);
                     setSystemAudioMode(false);
                     finishWithCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED);
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
index 78b40fd..01063b7 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
@@ -16,6 +16,7 @@
 
 package com.android.server.hdmi;
 
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 
 /**
@@ -48,7 +49,7 @@
                 mAvrAddress), new SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     tv().setSystemAudioMode(false, true);
                     finish();
                 }
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
index 2ae5c97..cab8439 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -19,9 +19,9 @@
 import android.annotation.Nullable;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.RemoteException;
 import android.util.Slog;
-
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 
 /**
@@ -56,7 +56,7 @@
                 new SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     handleSendGiveAudioStatusFailure();
                 }
             }
diff --git a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
index 16fc25f..525e223 100644
--- a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
+++ b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
@@ -22,10 +22,9 @@
 import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL;
 import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL;
 
+import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.util.Slog;
-
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
-
 import java.util.Arrays;
 
 /**
@@ -82,7 +81,7 @@
         sendCommand(message, new SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error != Constants.SEND_RESULT_SUCCESS) {
+                if (error != SendMessageResult.SUCCESS) {
                     tv().announceTimerRecordingResult(mRecorderAddress,
                             TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION);
                     finish();
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 3a9ff5f..a4b5e6a 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -67,10 +67,11 @@
     libhidl \
     libhwbinder \
     libutils \
-    android.hardware.power@1.0 \
-    android.hardware.vibrator@1.0 \
-    android.hardware.light@2.0 \
-    android.hardware.vr@1.0 \
     android.hardware.audio.common@2.0 \
-    android.hardware.tv.input@1.0 \
+    android.hardware.light@2.0 \
+    android.hardware.power@1.0 \
     android.hardware.thermal@1.0 \
+    android.hardware.tv.cec@1.0 \
+    android.hardware.tv.input@1.0 \
+    android.hardware.vibrator@1.0 \
+    android.hardware.vr@1.0 \
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index a23fbcb..0c5729e 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -21,16 +21,32 @@
 #include <JNIHelp.h>
 #include <ScopedPrimitiveArray.h>
 
-#include <cstring>
-
+#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
+#include <android/hardware/tv/cec/1.0/IHdmiCecCallback.h>
+#include <android/hardware/tv/cec/1.0/types.h>
 #include <android_os_MessageQueue.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/Log.h>
-#include <hardware/hdmi_cec.h>
 #include <sys/param.h>
+#include <utils/Errors.h>
 #include <utils/Looper.h>
 #include <utils/RefBase.h>
 
+using ::android::hardware::tv::cec::V1_0::CecLogicalAddress;
+using ::android::hardware::tv::cec::V1_0::CecMessage;
+using ::android::hardware::tv::cec::V1_0::HdmiPortInfo;
+using ::android::hardware::tv::cec::V1_0::HotplugEvent;
+using ::android::hardware::tv::cec::V1_0::IHdmiCec;
+using ::android::hardware::tv::cec::V1_0::IHdmiCecCallback;
+using ::android::hardware::tv::cec::V1_0::MaxLength;
+using ::android::hardware::tv::cec::V1_0::OptionKey;
+using ::android::hardware::tv::cec::V1_0::Result;
+using ::android::hardware::tv::cec::V1_0::SendMessageResult;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+
 namespace android {
 
 static struct {
@@ -40,15 +56,13 @@
 
 class HdmiCecController {
 public:
-    HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj,
-            const sp<Looper>& looper);
-
-    void init();
+    HdmiCecController(sp<IHdmiCec> hdmiCec, jobject callbacksObj, const sp<Looper>& looper);
+    ~HdmiCecController();
 
     // Send message to other device. Note that it runs in IO thread.
-    int sendMessage(const cec_message_t& message);
+    int sendMessage(const CecMessage& message);
     // Add a logical address to device.
-    int addLogicalAddress(cec_logical_address_t address);
+    int addLogicalAddress(CecLogicalAddress address);
     // Clear all logical address registered to the device.
     void clearLogicaladdress();
     // Get physical address of device.
@@ -59,10 +73,12 @@
     uint32_t getVendorId();
     // Get Port information on all the HDMI ports.
     jobjectArray getPortInfos();
-    // Set a flag and its value.
-    void setOption(int flag, int value);
-    // Set audio return channel status.
-    void setAudioReturnChannel(int port, bool flag);
+    // Set an option to CEC HAL.
+    void setOption(OptionKey key, bool enabled);
+    // Informs CEC HAL about the current system language.
+    void setLanguage(hidl_string language);
+    // Enable audio return channel.
+    void enableAudioReturnChannel(int port, bool flag);
     // Whether to hdmi device is connected to the given port.
     bool isConnected(int port);
 
@@ -71,69 +87,48 @@
     }
 
 private:
+    class HdmiCecCallback : public IHdmiCecCallback {
+    public:
+        HdmiCecCallback(HdmiCecController* controller) : mController(controller) {};
+        Return<void> onCecMessage(const CecMessage& event)  override;
+        Return<void> onHotplugEvent(const HotplugEvent& event)  override;
+    private:
+        HdmiCecController* mController;
+    };
+
     static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
-    static void onReceived(const hdmi_event_t* event, void* arg);
 
-    hdmi_cec_device_t* mDevice;
+    sp<IHdmiCec> mHdmiCec;
     jobject mCallbacksObj;
+    sp<IHdmiCecCallback> mHdmiCecCallback;
     sp<Looper> mLooper;
 };
 
-// RefBase wrapper for hdmi_event_t. As hdmi_event_t coming from HAL
-// may keep its own lifetime, we need to copy it in order to delegate
-// it to service thread.
-class CecEventWrapper : public LightRefBase<CecEventWrapper> {
-public:
-    explicit CecEventWrapper(const hdmi_event_t& event) {
-        // Copy message.
-        switch (event.type) {
-        case HDMI_EVENT_CEC_MESSAGE:
-            mEvent.cec.initiator = event.cec.initiator;
-            mEvent.cec.destination = event.cec.destination;
-            mEvent.cec.length = event.cec.length;
-            std::memcpy(mEvent.cec.body, event.cec.body, event.cec.length);
-            break;
-        case HDMI_EVENT_HOT_PLUG:
-            mEvent.hotplug.connected = event.hotplug.connected;
-            mEvent.hotplug.port_id = event.hotplug.port_id;
-            break;
-        default:
-            // TODO: add more type whenever new type is introduced.
-            break;
-        }
-    }
-
-    const cec_message_t& cec() const {
-        return mEvent.cec;
-    }
-
-    const hotplug_event_t& hotplug() const {
-        return mEvent.hotplug;
-    }
-
-    virtual ~CecEventWrapper() {}
-
-private:
-    hdmi_event_t mEvent;
-};
-
 // Handler class to delegate incoming message to service thread.
 class HdmiCecEventHandler : public MessageHandler {
 public:
-    HdmiCecEventHandler(HdmiCecController* controller, const sp<CecEventWrapper>& event)
-        : mController(controller),
-          mEventWrapper(event) {
-    }
+    enum EventType {
+        CEC_MESSAGE,
+        HOT_PLUG
+    };
+
+    HdmiCecEventHandler(HdmiCecController* controller, const CecMessage& cecMessage)
+            : mController(controller),
+              mCecMessage(cecMessage) {}
+
+    HdmiCecEventHandler(HdmiCecController* controller, const HotplugEvent& hotplugEvent)
+            : mController(controller),
+              mHotplugEvent(hotplugEvent) {}
 
     virtual ~HdmiCecEventHandler() {}
 
     void handleMessage(const Message& message) {
         switch (message.what) {
-        case HDMI_EVENT_CEC_MESSAGE:
-            propagateCecCommand(mEventWrapper->cec());
+        case EventType::CEC_MESSAGE:
+            propagateCecCommand(mCecMessage);
             break;
-        case HDMI_EVENT_HOT_PLUG:
-            propagateHotplugEvent(mEventWrapper->hotplug());
+        case EventType::HOT_PLUG:
+            propagateHotplugEvent(mHotplugEvent);
             break;
         default:
             // TODO: add more type whenever new type is introduced.
@@ -143,14 +138,13 @@
 
 private:
     // Propagate the message up to Java layer.
-    void propagateCecCommand(const cec_message_t& message) {
-        jint srcAddr = message.initiator;
-        jint dstAddr = message.destination;
+    void propagateCecCommand(const CecMessage& message) {
         JNIEnv* env = AndroidRuntime::getJNIEnv();
-        jbyteArray body = env->NewByteArray(message.length);
-        const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body);
-        env->SetByteArrayRegion(body, 0, message.length, bodyPtr);
-
+        jint srcAddr = static_cast<jint>(message.initiator);
+        jint dstAddr = static_cast<jint>(message.destination);
+        jbyteArray body = env->NewByteArray(message.body.size());
+        const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body.data());
+        env->SetByteArrayRegion(body, 0, message.body.size(), bodyPtr);
         env->CallVoidMethod(mController->getCallbacksObj(),
                 gHdmiCecControllerClassInfo.handleIncomingCecCommand, srcAddr,
                 dstAddr, body);
@@ -159,10 +153,10 @@
         checkAndClearExceptionFromCallback(env, __FUNCTION__);
     }
 
-    void propagateHotplugEvent(const hotplug_event_t& event) {
+    void propagateHotplugEvent(const HotplugEvent& event) {
         // Note that this method should be called in service thread.
         JNIEnv* env = AndroidRuntime::getJNIEnv();
-        jint port = event.port_id;
+        jint port = static_cast<jint>(event.portId);
         jboolean connected = (jboolean) event.connected;
         env->CallVoidMethod(mController->getCallbacksObj(),
                 gHdmiCecControllerClassInfo.handleHotplug, port, connected);
@@ -180,51 +174,83 @@
     }
 
     HdmiCecController* mController;
-    sp<CecEventWrapper> mEventWrapper;
+    CecMessage mCecMessage;
+    HotplugEvent mHotplugEvent;
 };
 
-HdmiCecController::HdmiCecController(hdmi_cec_device_t* device,
-        jobject callbacksObj, const sp<Looper>& looper) :
-    mDevice(device),
-    mCallbacksObj(callbacksObj),
-    mLooper(looper) {
+HdmiCecController::HdmiCecController(sp<IHdmiCec> hdmiCec,
+        jobject callbacksObj, const sp<Looper>& looper)
+        : mHdmiCec(hdmiCec),
+          mCallbacksObj(callbacksObj),
+          mLooper(looper) {
+    mHdmiCecCallback = new HdmiCecCallback(this);
+    Return<void> ret = mHdmiCec->setCallback(mHdmiCecCallback);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to set a cec callback.");
+    }
 }
 
-void HdmiCecController::init() {
-    mDevice->register_event_callback(mDevice, HdmiCecController::onReceived, this);
+HdmiCecController::~HdmiCecController() {
+    Return<void> ret = mHdmiCec->setCallback(nullptr);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to set a cec callback.");
+    }
 }
 
-int HdmiCecController::sendMessage(const cec_message_t& message) {
+int HdmiCecController::sendMessage(const CecMessage& message) {
     // TODO: propagate send_message's return value.
-    return mDevice->send_message(mDevice, &message);
+    Return<SendMessageResult> ret = mHdmiCec->sendMessage(message);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to send CEC message.");
+        return static_cast<int>(SendMessageResult::FAIL);
+    }
+    return static_cast<int>((SendMessageResult) ret);
 }
 
-int HdmiCecController::addLogicalAddress(cec_logical_address_t address) {
-    return mDevice->add_logical_address(mDevice, address);
+int HdmiCecController::addLogicalAddress(CecLogicalAddress address) {
+    Return<Result> ret = mHdmiCec->addLogicalAddress(address);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to add a logical address.");
+        return static_cast<int>(Result::FAILURE_UNKNOWN);
+    }
+    return static_cast<int>((Result) ret);
 }
 
 void HdmiCecController::clearLogicaladdress() {
-    mDevice->clear_logical_address(mDevice);
+    Return<void> ret = mHdmiCec->clearLogicalAddress();
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to clear logical address.");
+    }
 }
 
 int HdmiCecController::getPhysicalAddress() {
+    Result result;
     uint16_t addr;
-    if (!mDevice->get_physical_address(mDevice, &addr)) {
-        return addr;
+    Return<void> ret = mHdmiCec->getPhysicalAddress([&result, &addr](Result res, uint16_t paddr) {
+            result = res;
+            addr = paddr;
+        });
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to get physical address.");
+        return INVALID_PHYSICAL_ADDRESS;
     }
-    return INVALID_PHYSICAL_ADDRESS;
+    return result == Result::SUCCESS ? addr : INVALID_PHYSICAL_ADDRESS;
 }
 
 int HdmiCecController::getVersion() {
-    int version = 0;
-    mDevice->get_version(mDevice, &version);
-    return version;
+    Return<int32_t> ret = mHdmiCec->getCecVersion();
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to get cec version.");
+    }
+    return ret;
 }
 
 uint32_t HdmiCecController::getVendorId() {
-    uint32_t vendorId = 0;
-    mDevice->get_vendor_id(mDevice, &vendorId);
-    return vendorId;
+    Return<uint32_t> ret = mHdmiCec->getVendorId();
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to get vendor id.");
+    }
+    return ret;
 }
 
 jobjectArray HdmiCecController::getPortInfos() {
@@ -237,48 +263,69 @@
     if (ctor == NULL) {
         return NULL;
     }
-    hdmi_port_info* ports;
-    int numPorts;
-    mDevice->get_port_info(mDevice, &ports, &numPorts);
-    jobjectArray res = env->NewObjectArray(numPorts, hdmiPortInfo, NULL);
+    hidl_vec<HdmiPortInfo> ports;
+    Return<void> ret = mHdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) {
+            ports = list;
+        });
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to get port information.");
+        return NULL;
+    }
+    jobjectArray res = env->NewObjectArray(ports.size(), hdmiPortInfo, NULL);
 
     // MHL support field will be obtained from MHL HAL. Leave it to false.
     jboolean mhlSupported = (jboolean) 0;
-    for (int i = 0; i < numPorts; ++i) {
-        hdmi_port_info* info = &ports[i];
-        jboolean cecSupported = (jboolean) info->cec_supported;
-        jboolean arcSupported = (jboolean) info->arc_supported;
-        jobject infoObj = env->NewObject(hdmiPortInfo, ctor, info->port_id, info->type,
-                info->physical_address, cecSupported, mhlSupported, arcSupported);
+    for (size_t i = 0; i < ports.size(); ++i) {
+        jboolean cecSupported = (jboolean) ports[i].cecSupported;
+        jboolean arcSupported = (jboolean) ports[i].arcSupported;
+        jobject infoObj = env->NewObject(hdmiPortInfo, ctor, ports[i].portId, ports[i].type,
+                ports[i].physicalAddress, cecSupported, mhlSupported, arcSupported);
         env->SetObjectArrayElement(res, i, infoObj);
     }
     return res;
 }
 
-void HdmiCecController::setOption(int flag, int value) {
-    mDevice->set_option(mDevice, flag, value);
+void HdmiCecController::setOption(OptionKey key, bool enabled) {
+    Return<void> ret = mHdmiCec->setOption(key, enabled);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to set option.");
+    }
 }
 
-// Set audio return channel status.
-  void HdmiCecController::setAudioReturnChannel(int port, bool enabled) {
-    mDevice->set_audio_return_channel(mDevice, port, enabled ? 1 : 0);
+void HdmiCecController::setLanguage(hidl_string language) {
+    Return<void> ret = mHdmiCec->setLanguage(language);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to set language.");
+    }
+}
+
+// Enable audio return channel.
+void HdmiCecController::enableAudioReturnChannel(int port, bool enabled) {
+    Return<void> ret = mHdmiCec->enableAudioReturnChannel(port, enabled);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to enable/disable ARC.");
+    }
 }
 
 // Whether to hdmi device is connected to the given port.
 bool HdmiCecController::isConnected(int port) {
-    return mDevice->is_connected(mDevice, port) == HDMI_CONNECTED;
+    Return<bool> ret = mHdmiCec->isConnected(port);
+    if (!ret.getStatus().isOk()) {
+        ALOGE("Failed to get connection info.");
+    }
+    return ret;
 }
 
-// static
-void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
-    HdmiCecController* controller = static_cast<HdmiCecController*>(arg);
-    if (controller == NULL) {
-        return;
-    }
+Return<void> HdmiCecController::HdmiCecCallback::onCecMessage(const CecMessage& message) {
+    sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(mController, message));
+    mController->mLooper->sendMessage(handler, HdmiCecEventHandler::EventType::CEC_MESSAGE);
+    return Void();
+}
 
-    sp<CecEventWrapper> spEvent(new CecEventWrapper(*event));
-    sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(controller, spEvent));
-    controller->mLooper->sendMessage(handler, event->type);
+Return<void> HdmiCecController::HdmiCecCallback::onHotplugEvent(const HotplugEvent& event) {
+    sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(mController, event));
+    mController->mLooper->sendMessage(handler, HdmiCecEventHandler::EventType::HOT_PLUG);
+    return Void();
 }
 
 //------------------------------------------------------------------------------
@@ -288,30 +335,19 @@
 
 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj,
         jobject messageQueueObj) {
-    int err;
-    hw_module_t* module;
-    err = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID,
-            const_cast<const hw_module_t **>(&module));
-    if (err != 0) {
-        ALOGE("Error acquiring hardware module: %d", err);
+    // TODO(b/31632518)
+    sp<IHdmiCec> hdmiCec = IHdmiCec::getService("tv.cec");
+    if (hdmiCec == nullptr) {
+        ALOGE("Couldn't get tv.cec service.");
         return 0;
     }
-
-    hw_device_t* device;
-    err = module->methods->open(module, HDMI_CEC_HARDWARE_INTERFACE, &device);
-    if (err != 0) {
-        ALOGE("Error opening hardware module: %d", err);
-        return 0;
-    }
-
     sp<MessageQueue> messageQueue =
             android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
 
     HdmiCecController* controller = new HdmiCecController(
-            reinterpret_cast<hdmi_cec_device*>(device),
+            hdmiCec,
             env->NewGlobalRef(callbacksObj),
             messageQueue->getLooper());
-    controller->init();
 
     GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz,
             "handleIncomingCecCommand", "(II[B)V");
@@ -323,14 +359,18 @@
 
 static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr,
         jint srcAddr, jint dstAddr, jbyteArray body) {
-    cec_message_t message;
-    message.initiator = static_cast<cec_logical_address_t>(srcAddr);
-    message.destination = static_cast<cec_logical_address_t>(dstAddr);
+    CecMessage message;
+    message.initiator = static_cast<CecLogicalAddress>(srcAddr);
+    message.destination = static_cast<CecLogicalAddress>(dstAddr);
 
     jsize len = env->GetArrayLength(body);
-    message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH);
     ScopedByteArrayRO bodyPtr(env, body);
-    std::memcpy(message.body, bodyPtr.get(), message.length);
+    size_t bodyLength = MIN(static_cast<size_t>(len),
+            static_cast<size_t>(MaxLength::MESSAGE_BODY));
+    message.body.resize(bodyLength);
+    for (size_t i = 0; i < bodyLength; ++i) {
+        message.body[i] = static_cast<uint8_t>(bodyPtr[i]);
+    }
 
     HdmiCecController* controller =
             reinterpret_cast<HdmiCecController*>(controllerPtr);
@@ -340,7 +380,7 @@
 static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr,
         jint logicalAddress) {
     HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
-    return controller->addLogicalAddress(static_cast<cec_logical_address_t>(logicalAddress));
+    return controller->addLogicalAddress(static_cast<CecLogicalAddress>(logicalAddress));
 }
 
 static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
@@ -370,13 +410,20 @@
 
 static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) {
     HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
-    controller->setOption(flag, value);
+    controller->setOption(static_cast<OptionKey>(flag), value > 0 ? true : false);
 }
 
-static void nativeSetAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
+static void nativeSetLanguage(JNIEnv* env, jclass clazz, jlong controllerPtr, jstring language) {
+    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+    const char *languageStr = env->GetStringUTFChars(language, NULL);
+    controller->setLanguage(languageStr);
+    env->ReleaseStringUTFChars(language, languageStr);
+}
+
+static void nativeEnableAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
         jint port, jboolean enabled) {
     HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
-    controller->setAudioReturnChannel(port, enabled == JNI_TRUE);
+    controller->enableAudioReturnChannel(port, enabled == JNI_TRUE);
 }
 
 static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) {
@@ -398,8 +445,9 @@
     { "nativeGetPortInfos",
       "(J)[Landroid/hardware/hdmi/HdmiPortInfo;",
       (void *) nativeGetPortInfos },
-    { "nativeSetOption", "(JII)V", (void *) nativeSetOption },
-    { "nativeSetAudioReturnChannel", "(JIZ)V", (void *) nativeSetAudioReturnChannel },
+    { "nativeSetOption", "(JIZ)V", (void *) nativeSetOption },
+    { "nativeSetLanguage", "(JLjava/lang/String;)V", (void *) nativeSetLanguage },
+    { "nativeEnableAudioReturnChannel", "(JIZ)V", (void *) nativeEnableAudioReturnChannel },
     { "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected },
 };