10792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/*
20792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Copyright (C) 2014 The Android Open Source Project
30792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang *
40792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Licensed under the Apache License, Version 2.0 (the "License");
50792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * you may not use this file except in compliance with the License.
60792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * You may obtain a copy of the License at
70792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang *
80792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang *      http://www.apache.org/licenses/LICENSE-2.0
90792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang *
100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Unless required by applicable law or agreed to in writing, software
110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * distributed under the License is distributed on an "AS IS" BASIS,
120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * See the License for the specific language governing permissions and
140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * limitations under the License.
150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */
160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang#define LOG_TAG "HdmiCecControllerJni"
180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
190792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang#define LOG_NDEBUG 1
200792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
212279b2534272282a5b5152723235da397e49195cSteven Moreland#include <nativehelper/JNIHelp.h>
222279b2534272282a5b5152723235da397e49195cSteven Moreland#include <nativehelper/ScopedPrimitiveArray.h>
23e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
24bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
25bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho#include <android/hardware/tv/cec/1.0/IHdmiCecCallback.h>
26bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho#include <android/hardware/tv/cec/1.0/types.h>
274085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang#include <android_os_MessageQueue.h>
280792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang#include <android_runtime/AndroidRuntime.h>
290792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang#include <android_runtime/Log.h>
30e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang#include <sys/param.h>
31bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho#include <utils/Errors.h>
324085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang#include <utils/Looper.h>
334085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang#include <utils/RefBase.h>
340792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
35bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::tv::cec::V1_0::CecLogicalAddress;
36bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::tv::cec::V1_0::CecMessage;
37bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::tv::cec::V1_0::HdmiPortInfo;
38bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::tv::cec::V1_0::HotplugEvent;
39bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::tv::cec::V1_0::IHdmiCec;
40bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::tv::cec::V1_0::IHdmiCecCallback;
41bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::tv::cec::V1_0::MaxLength;
42bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::tv::cec::V1_0::OptionKey;
43bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::tv::cec::V1_0::Result;
44bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::tv::cec::V1_0::SendMessageResult;
45bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::Return;
46bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::Void;
47bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::hidl_vec;
48bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chousing ::android::hardware::hidl_string;
49bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho
500792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangnamespace android {
510792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
520792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangstatic struct {
53e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    jmethodID handleIncomingCecCommand;
54e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    jmethodID handleHotplug;
550792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} gHdmiCecControllerClassInfo;
560792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
570792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangclass HdmiCecController {
580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic:
59bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    HdmiCecController(sp<IHdmiCec> hdmiCec, jobject callbacksObj, const sp<Looper>& looper);
60bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    ~HdmiCecController();
61e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
62e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    // Send message to other device. Note that it runs in IO thread.
63bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    int sendMessage(const CecMessage& message);
64a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    // Add a logical address to device.
65bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    int addLogicalAddress(CecLogicalAddress address);
66a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    // Clear all logical address registered to the device.
67a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    void clearLogicaladdress();
68a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    // Get physical address of device.
69a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    int getPhysicalAddress();
70a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    // Get CEC version from driver.
71a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    int getVersion();
72a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    // Get vendor id used for vendor command.
73a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    uint32_t getVendorId();
740340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    // Get Port information on all the HDMI ports.
750340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    jobjectArray getPortInfos();
76bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    // Set an option to CEC HAL.
77bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    void setOption(OptionKey key, bool enabled);
78bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    // Informs CEC HAL about the current system language.
79bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    void setLanguage(hidl_string language);
80bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    // Enable audio return channel.
81bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    void enableAudioReturnChannel(int port, bool flag);
82092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    // Whether to hdmi device is connected to the given port.
83092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    bool isConnected(int port);
840792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
854085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    jobject getCallbacksObj() const {
864085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        return mCallbacksObj;
874085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
88e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
894085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangprivate:
90bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    class HdmiCecCallback : public IHdmiCecCallback {
91bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    public:
92bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        HdmiCecCallback(HdmiCecController* controller) : mController(controller) {};
93bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        Return<void> onCecMessage(const CecMessage& event)  override;
94bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        Return<void> onHotplugEvent(const HotplugEvent& event)  override;
95bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    private:
96bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        HdmiCecController* mController;
97bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    };
98bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho
99a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
1000792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
101bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    sp<IHdmiCec> mHdmiCec;
1020792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    jobject mCallbacksObj;
103bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    sp<IHdmiCecCallback> mHdmiCecCallback;
1044085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    sp<Looper> mLooper;
1050792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang};
1060792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
1074085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang// Handler class to delegate incoming message to service thread.
1084085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangclass HdmiCecEventHandler : public MessageHandler {
1094085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangpublic:
110bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    enum EventType {
111bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        CEC_MESSAGE,
112bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        HOT_PLUG
113bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    };
114bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho
115bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    HdmiCecEventHandler(HdmiCecController* controller, const CecMessage& cecMessage)
116bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho            : mController(controller),
117bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho              mCecMessage(cecMessage) {}
118bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho
119bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    HdmiCecEventHandler(HdmiCecController* controller, const HotplugEvent& hotplugEvent)
120bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho            : mController(controller),
121bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho              mHotplugEvent(hotplugEvent) {}
1224085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1234085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    virtual ~HdmiCecEventHandler() {}
1244085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1254085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    void handleMessage(const Message& message) {
1264085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        switch (message.what) {
127bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        case EventType::CEC_MESSAGE:
128bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho            propagateCecCommand(mCecMessage);
1294085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            break;
130bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        case EventType::HOT_PLUG:
131bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho            propagateHotplugEvent(mHotplugEvent);
1324085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            break;
1334085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        default:
1344085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            // TODO: add more type whenever new type is introduced.
1354085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            break;
1364085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        }
1374085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
138e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
1394085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangprivate:
1404085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    // Propagate the message up to Java layer.
141bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    void propagateCecCommand(const CecMessage& message) {
1424085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        JNIEnv* env = AndroidRuntime::getJNIEnv();
143bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        jint srcAddr = static_cast<jint>(message.initiator);
144bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        jint dstAddr = static_cast<jint>(message.destination);
145bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        jbyteArray body = env->NewByteArray(message.body.size());
146bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body.data());
147bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        env->SetByteArrayRegion(body, 0, message.body.size(), bodyPtr);
1484085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        env->CallVoidMethod(mController->getCallbacksObj(),
1494085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang                gHdmiCecControllerClassInfo.handleIncomingCecCommand, srcAddr,
1504085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang                dstAddr, body);
1514085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        env->DeleteLocalRef(body);
1524085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1534085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        checkAndClearExceptionFromCallback(env, __FUNCTION__);
1544085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
1554085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
156bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    void propagateHotplugEvent(const HotplugEvent& event) {
1574085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        // Note that this method should be called in service thread.
1584085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        JNIEnv* env = AndroidRuntime::getJNIEnv();
159bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        jint port = static_cast<jint>(event.portId);
16042230728b8212738c2351939c5577730f05a58deJungshik Jang        jboolean connected = (jboolean) event.connected;
1614085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        env->CallVoidMethod(mController->getCallbacksObj(),
16242230728b8212738c2351939c5577730f05a58deJungshik Jang                gHdmiCecControllerClassInfo.handleHotplug, port, connected);
1634085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1644085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        checkAndClearExceptionFromCallback(env, __FUNCTION__);
1654085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
1664085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1674085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    // static
1684085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
1694085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        if (env->ExceptionCheck()) {
1704085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            ALOGE("An exception was thrown by callback '%s'.", methodName);
1714085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            LOGE_EX(env);
1724085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            env->ExceptionClear();
1734085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        }
1744085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
1754085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1764085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    HdmiCecController* mController;
177bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    CecMessage mCecMessage;
178bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    HotplugEvent mHotplugEvent;
1794085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang};
1804085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
181bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun ChoHdmiCecController::HdmiCecController(sp<IHdmiCec> hdmiCec,
182bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        jobject callbacksObj, const sp<Looper>& looper)
183bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        : mHdmiCec(hdmiCec),
184bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho          mCallbacksObj(callbacksObj),
185bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho          mLooper(looper) {
186bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    mHdmiCecCallback = new HdmiCecCallback(this);
187bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Return<void> ret = mHdmiCec->setCallback(mHdmiCecCallback);
188d002a8b07becc7ce1b0978b837bd61f29f8c4d18Steven Moreland    if (!ret.isOk()) {
189bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Failed to set a cec callback.");
190bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    }
1914085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang}
1924085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
193bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun ChoHdmiCecController::~HdmiCecController() {
194bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Return<void> ret = mHdmiCec->setCallback(nullptr);
195d002a8b07becc7ce1b0978b837bd61f29f8c4d18Steven Moreland    if (!ret.isOk()) {
196bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Failed to set a cec callback.");
197bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    }
198e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang}
199e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
200bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Choint HdmiCecController::sendMessage(const CecMessage& message) {
201e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    // TODO: propagate send_message's return value.
202bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Return<SendMessageResult> ret = mHdmiCec->sendMessage(message);
203d002a8b07becc7ce1b0978b837bd61f29f8c4d18Steven Moreland    if (!ret.isOk()) {
204bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Failed to send CEC message.");
205bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        return static_cast<int>(SendMessageResult::FAIL);
206bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    }
207bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    return static_cast<int>((SendMessageResult) ret);
208e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang}
209e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
210bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Choint HdmiCecController::addLogicalAddress(CecLogicalAddress address) {
211bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Return<Result> ret = mHdmiCec->addLogicalAddress(address);
212d002a8b07becc7ce1b0978b837bd61f29f8c4d18Steven Moreland    if (!ret.isOk()) {
213bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Failed to add a logical address.");
214bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        return static_cast<int>(Result::FAILURE_UNKNOWN);
215bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    }
216bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    return static_cast<int>((Result) ret);
217a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
218a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
219a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jangvoid HdmiCecController::clearLogicaladdress() {
220bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Return<void> ret = mHdmiCec->clearLogicalAddress();
221d002a8b07becc7ce1b0978b837bd61f29f8c4d18Steven Moreland    if (!ret.isOk()) {
222bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Failed to clear logical address.");
223bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    }
224a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
225a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
226a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jangint HdmiCecController::getPhysicalAddress() {
227bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Result result;
228a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    uint16_t addr;
229bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Return<void> ret = mHdmiCec->getPhysicalAddress([&result, &addr](Result res, uint16_t paddr) {
230bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho            result = res;
231bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho            addr = paddr;
232bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        });
233d002a8b07becc7ce1b0978b837bd61f29f8c4d18Steven Moreland    if (!ret.isOk()) {
234bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Failed to get physical address.");
235bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        return INVALID_PHYSICAL_ADDRESS;
236a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    }
237bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    return result == Result::SUCCESS ? addr : INVALID_PHYSICAL_ADDRESS;
238a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
239a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
240a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jangint HdmiCecController::getVersion() {
241bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Return<int32_t> ret = mHdmiCec->getCecVersion();
242d002a8b07becc7ce1b0978b837bd61f29f8c4d18Steven Moreland    if (!ret.isOk()) {
243bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Failed to get cec version.");
244bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    }
245bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    return ret;
246a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
247a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
248a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Janguint32_t HdmiCecController::getVendorId() {
249bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Return<uint32_t> ret = mHdmiCec->getVendorId();
250d002a8b07becc7ce1b0978b837bd61f29f8c4d18Steven Moreland    if (!ret.isOk()) {
251bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Failed to get vendor id.");
252bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    }
253bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    return ret;
254a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
255a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
2560340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk KimjobjectArray HdmiCecController::getPortInfos() {
2570340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    JNIEnv* env = AndroidRuntime::getJNIEnv();
25863dd3bb3602bc00557680432b08b49a5a15bcdb7Jinsuk Kim    jclass hdmiPortInfo = env->FindClass("android/hardware/hdmi/HdmiPortInfo");
2590340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    if (hdmiPortInfo == NULL) {
2600340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        return NULL;
2610340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    }
2620340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    jmethodID ctor = env->GetMethodID(hdmiPortInfo, "<init>", "(IIIZZZ)V");
2630340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    if (ctor == NULL) {
2640340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        return NULL;
2650340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    }
266bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    hidl_vec<HdmiPortInfo> ports;
267bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Return<void> ret = mHdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) {
268bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho            ports = list;
269bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        });
270d002a8b07becc7ce1b0978b837bd61f29f8c4d18Steven Moreland    if (!ret.isOk()) {
271bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Failed to get port information.");
272bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        return NULL;
273bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    }
274bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    jobjectArray res = env->NewObjectArray(ports.size(), hdmiPortInfo, NULL);
2750340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim
2760340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    // MHL support field will be obtained from MHL HAL. Leave it to false.
2770340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    jboolean mhlSupported = (jboolean) 0;
278bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    for (size_t i = 0; i < ports.size(); ++i) {
279bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        jboolean cecSupported = (jboolean) ports[i].cecSupported;
280bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        jboolean arcSupported = (jboolean) ports[i].arcSupported;
281bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        jobject infoObj = env->NewObject(hdmiPortInfo, ctor, ports[i].portId, ports[i].type,
282bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho                ports[i].physicalAddress, cecSupported, mhlSupported, arcSupported);
2830340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        env->SetObjectArrayElement(res, i, infoObj);
2840340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    }
2850340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    return res;
2860340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim}
2870340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim
288bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chovoid HdmiCecController::setOption(OptionKey key, bool enabled) {
289bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Return<void> ret = mHdmiCec->setOption(key, enabled);
290d002a8b07becc7ce1b0978b837bd61f29f8c4d18Steven Moreland    if (!ret.isOk()) {
291bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Failed to set option.");
292bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    }
293092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang}
294092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
295bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chovoid HdmiCecController::setLanguage(hidl_string language) {
296bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Return<void> ret = mHdmiCec->setLanguage(language);
297d002a8b07becc7ce1b0978b837bd61f29f8c4d18Steven Moreland    if (!ret.isOk()) {
298bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Failed to set language.");
299bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    }
300bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho}
301bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho
302bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho// Enable audio return channel.
303bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chovoid HdmiCecController::enableAudioReturnChannel(int port, bool enabled) {
304bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Return<void> ret = mHdmiCec->enableAudioReturnChannel(port, enabled);
305d002a8b07becc7ce1b0978b837bd61f29f8c4d18Steven Moreland    if (!ret.isOk()) {
306bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Failed to enable/disable ARC.");
307bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    }
308092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang}
309092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
310092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang// Whether to hdmi device is connected to the given port.
311092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jangbool HdmiCecController::isConnected(int port) {
312bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    Return<bool> ret = mHdmiCec->isConnected(port);
313d002a8b07becc7ce1b0978b837bd61f29f8c4d18Steven Moreland    if (!ret.isOk()) {
314bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Failed to get connection info.");
315bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    }
316bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    return ret;
317092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang}
318092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
319bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun ChoReturn<void> HdmiCecController::HdmiCecCallback::onCecMessage(const CecMessage& message) {
320bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(mController, message));
321bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    mController->mLooper->sendMessage(handler, HdmiCecEventHandler::EventType::CEC_MESSAGE);
322bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    return Void();
323bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho}
3240792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
325bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun ChoReturn<void> HdmiCecController::HdmiCecCallback::onHotplugEvent(const HotplugEvent& event) {
326bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(mController, event));
327bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    mController->mLooper->sendMessage(handler, HdmiCecEventHandler::EventType::HOT_PLUG);
328bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    return Void();
3290792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang}
3300792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
3310792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang//------------------------------------------------------------------------------
332e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
333e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
3346c89616c388d2e5cac5f7d0c1682e48fa6ea7d31Chih-Hung Hsieh        LOG_FATAL_IF(! (var), "Unable to find method " methodName);
335e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
3364085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangstatic jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj,
3374085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        jobject messageQueueObj) {
338bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    // TODO(b/31632518)
3397e6627eade85a1861ad5ca55200301cd7799e4e1Chris Phoenix    sp<IHdmiCec> hdmiCec = IHdmiCec::getService();
340bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    if (hdmiCec == nullptr) {
341bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        ALOGE("Couldn't get tv.cec service.");
342e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        return 0;
343e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
3444085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    sp<MessageQueue> messageQueue =
3454085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
3464085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
3470792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    HdmiCecController* controller = new HdmiCecController(
348bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho            hdmiCec,
3494085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            env->NewGlobalRef(callbacksObj),
3504085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            messageQueue->getLooper());
351e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
352e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz,
353e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            "handleIncomingCecCommand", "(II[B)V");
354e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    GET_METHOD_ID(gHdmiCecControllerClassInfo.handleHotplug, clazz,
35542230728b8212738c2351939c5577730f05a58deJungshik Jang            "handleHotplug", "(IZ)V");
3560792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
3570792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    return reinterpret_cast<jlong>(controller);
3580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang}
3590792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
360e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangstatic jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr,
361e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        jint srcAddr, jint dstAddr, jbyteArray body) {
362bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    CecMessage message;
363bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    message.initiator = static_cast<CecLogicalAddress>(srcAddr);
364bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    message.destination = static_cast<CecLogicalAddress>(dstAddr);
365e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
366e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    jsize len = env->GetArrayLength(body);
367e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    ScopedByteArrayRO bodyPtr(env, body);
368bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    size_t bodyLength = MIN(static_cast<size_t>(len),
369bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho            static_cast<size_t>(MaxLength::MESSAGE_BODY));
370bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    message.body.resize(bodyLength);
371bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    for (size_t i = 0; i < bodyLength; ++i) {
372bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho        message.body[i] = static_cast<uint8_t>(bodyPtr[i]);
373bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    }
374e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
375e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    HdmiCecController* controller =
376e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            reinterpret_cast<HdmiCecController*>(controllerPtr);
377e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    return controller->sendMessage(message);
378e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang}
379e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
380a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimstatic jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr,
381a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        jint logicalAddress) {
382a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
383bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    return controller->addLogicalAddress(static_cast<CecLogicalAddress>(logicalAddress));
384a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
385a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
386a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimstatic void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
387a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
388a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    controller->clearLogicaladdress();
389a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
390a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
391a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimstatic jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
392a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
393a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    return controller->getPhysicalAddress();
394a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
395a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
396a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimstatic jint nativeGetVersion(JNIEnv* env, jclass clazz, jlong controllerPtr) {
397a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
398a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    return controller->getVersion();
399a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
400a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
401a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jangstatic jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) {
402a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
403a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    return controller->getVendorId();
404a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
405a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
4060340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimstatic jobjectArray nativeGetPortInfos(JNIEnv* env, jclass clazz, jlong controllerPtr) {
4070340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
4080340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    return controller->getPortInfos();
4090340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim}
4100340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim
411a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimstatic void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) {
412a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
413bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    controller->setOption(static_cast<OptionKey>(flag), value > 0 ? true : false);
414bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho}
415bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho
416bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chostatic void nativeSetLanguage(JNIEnv* env, jclass clazz, jlong controllerPtr, jstring language) {
417bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
418bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    const char *languageStr = env->GetStringUTFChars(language, NULL);
419bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    controller->setLanguage(languageStr);
420bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    env->ReleaseStringUTFChars(language, languageStr);
421092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang}
422092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
423bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Chostatic void nativeEnableAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
4241481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim        jint port, jboolean enabled) {
425a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
426bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    controller->enableAudioReturnChannel(port, enabled == JNI_TRUE);
427092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang}
428092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
429092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jangstatic jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) {
430a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
431092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ;
432092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang}
433092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
43476f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod sMethods[] = {
4350792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    /* name, signature, funcPtr */
4364085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    { "nativeInit",
4374085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang      "(Lcom/android/server/hdmi/HdmiCecController;Landroid/os/MessageQueue;)J",
4384085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang      (void *) nativeInit },
439a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    { "nativeSendCecCommand", "(JII[B)I", (void *) nativeSendCecCommand },
440a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    { "nativeAddLogicalAddress", "(JI)I", (void *) nativeAddLogicalAddress },
441a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    { "nativeClearLogicalAddress", "(J)V", (void *) nativeClearLogicalAddress },
442a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    { "nativeGetPhysicalAddress", "(J)I", (void *) nativeGetPhysicalAddress },
443a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    { "nativeGetVersion", "(J)I", (void *) nativeGetVersion },
444a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    { "nativeGetVendorId", "(J)I", (void *) nativeGetVendorId },
4450340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    { "nativeGetPortInfos",
44663dd3bb3602bc00557680432b08b49a5a15bcdb7Jinsuk Kim      "(J)[Landroid/hardware/hdmi/HdmiPortInfo;",
4470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim      (void *) nativeGetPortInfos },
448bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    { "nativeSetOption", "(JIZ)V", (void *) nativeSetOption },
449bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    { "nativeSetLanguage", "(JLjava/lang/String;)V", (void *) nativeSetLanguage },
450bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho    { "nativeEnableAudioReturnChannel", "(JIZ)V", (void *) nativeEnableAudioReturnChannel },
451092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    { "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected },
4520792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang};
4530792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
4540792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang#define CLASS_PATH "com/android/server/hdmi/HdmiCecController"
4550792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
4560792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangint register_android_server_hdmi_HdmiCecController(JNIEnv* env) {
457a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods));
4580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
4594048a4bcb1ea709ddb83a4fde3ff5c53e642f7d0Bernhard Rosenkränzer    (void)res; // Don't scream about unused variable in the LOG_NDEBUG case
4600792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    return 0;
4610792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang}
4620792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
4630792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang}  /* namespace android */
464