Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2014 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #define LOG_TAG "HdmiCecControllerJni" |
| 18 | |
| 19 | #define LOG_NDEBUG 1 |
| 20 | |
Steven Moreland | 2279b25 | 2017-07-19 09:50:45 -0700 | [diff] [blame] | 21 | #include <nativehelper/JNIHelp.h> |
| 22 | #include <nativehelper/ScopedPrimitiveArray.h> |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 23 | |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 24 | #include <android/hardware/tv/cec/1.0/IHdmiCec.h> |
| 25 | #include <android/hardware/tv/cec/1.0/IHdmiCecCallback.h> |
| 26 | #include <android/hardware/tv/cec/1.0/types.h> |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 27 | #include <android_os_MessageQueue.h> |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 28 | #include <android_runtime/AndroidRuntime.h> |
| 29 | #include <android_runtime/Log.h> |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 30 | #include <sys/param.h> |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 31 | #include <utils/Errors.h> |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 32 | #include <utils/Looper.h> |
| 33 | #include <utils/RefBase.h> |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 34 | |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 35 | using ::android::hardware::tv::cec::V1_0::CecLogicalAddress; |
| 36 | using ::android::hardware::tv::cec::V1_0::CecMessage; |
| 37 | using ::android::hardware::tv::cec::V1_0::HdmiPortInfo; |
| 38 | using ::android::hardware::tv::cec::V1_0::HotplugEvent; |
| 39 | using ::android::hardware::tv::cec::V1_0::IHdmiCec; |
| 40 | using ::android::hardware::tv::cec::V1_0::IHdmiCecCallback; |
| 41 | using ::android::hardware::tv::cec::V1_0::MaxLength; |
| 42 | using ::android::hardware::tv::cec::V1_0::OptionKey; |
| 43 | using ::android::hardware::tv::cec::V1_0::Result; |
| 44 | using ::android::hardware::tv::cec::V1_0::SendMessageResult; |
| 45 | using ::android::hardware::Return; |
| 46 | using ::android::hardware::Void; |
| 47 | using ::android::hardware::hidl_vec; |
| 48 | using ::android::hardware::hidl_string; |
| 49 | |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 50 | namespace android { |
| 51 | |
| 52 | static struct { |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 53 | jmethodID handleIncomingCecCommand; |
| 54 | jmethodID handleHotplug; |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 55 | } gHdmiCecControllerClassInfo; |
| 56 | |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 57 | class HdmiCecController { |
| 58 | public: |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 59 | HdmiCecController(sp<IHdmiCec> hdmiCec, jobject callbacksObj, const sp<Looper>& looper); |
| 60 | ~HdmiCecController(); |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 61 | |
| 62 | // Send message to other device. Note that it runs in IO thread. |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 63 | int sendMessage(const CecMessage& message); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 64 | // Add a logical address to device. |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 65 | int addLogicalAddress(CecLogicalAddress address); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 66 | // Clear all logical address registered to the device. |
| 67 | void clearLogicaladdress(); |
| 68 | // Get physical address of device. |
| 69 | int getPhysicalAddress(); |
| 70 | // Get CEC version from driver. |
| 71 | int getVersion(); |
| 72 | // Get vendor id used for vendor command. |
| 73 | uint32_t getVendorId(); |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 74 | // Get Port information on all the HDMI ports. |
| 75 | jobjectArray getPortInfos(); |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 76 | // Set an option to CEC HAL. |
| 77 | void setOption(OptionKey key, bool enabled); |
| 78 | // Informs CEC HAL about the current system language. |
| 79 | void setLanguage(hidl_string language); |
| 80 | // Enable audio return channel. |
| 81 | void enableAudioReturnChannel(int port, bool flag); |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 82 | // Whether to hdmi device is connected to the given port. |
| 83 | bool isConnected(int port); |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 84 | |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 85 | jobject getCallbacksObj() const { |
| 86 | return mCallbacksObj; |
| 87 | } |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 88 | |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 89 | private: |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 90 | class HdmiCecCallback : public IHdmiCecCallback { |
| 91 | public: |
| 92 | HdmiCecCallback(HdmiCecController* controller) : mController(controller) {}; |
| 93 | Return<void> onCecMessage(const CecMessage& event) override; |
| 94 | Return<void> onHotplugEvent(const HotplugEvent& event) override; |
| 95 | private: |
| 96 | HdmiCecController* mController; |
| 97 | }; |
| 98 | |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 99 | static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF; |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 100 | |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 101 | sp<IHdmiCec> mHdmiCec; |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 102 | jobject mCallbacksObj; |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 103 | sp<IHdmiCecCallback> mHdmiCecCallback; |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 104 | sp<Looper> mLooper; |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 105 | }; |
| 106 | |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 107 | // Handler class to delegate incoming message to service thread. |
| 108 | class HdmiCecEventHandler : public MessageHandler { |
| 109 | public: |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 110 | enum EventType { |
| 111 | CEC_MESSAGE, |
| 112 | HOT_PLUG |
| 113 | }; |
| 114 | |
| 115 | HdmiCecEventHandler(HdmiCecController* controller, const CecMessage& cecMessage) |
| 116 | : mController(controller), |
| 117 | mCecMessage(cecMessage) {} |
| 118 | |
| 119 | HdmiCecEventHandler(HdmiCecController* controller, const HotplugEvent& hotplugEvent) |
| 120 | : mController(controller), |
| 121 | mHotplugEvent(hotplugEvent) {} |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 122 | |
| 123 | virtual ~HdmiCecEventHandler() {} |
| 124 | |
| 125 | void handleMessage(const Message& message) { |
| 126 | switch (message.what) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 127 | case EventType::CEC_MESSAGE: |
| 128 | propagateCecCommand(mCecMessage); |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 129 | break; |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 130 | case EventType::HOT_PLUG: |
| 131 | propagateHotplugEvent(mHotplugEvent); |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 132 | break; |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 133 | default: |
| 134 | // TODO: add more type whenever new type is introduced. |
| 135 | break; |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | private: |
| 140 | // Propagate the message up to Java layer. |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 141 | void propagateCecCommand(const CecMessage& message) { |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 142 | JNIEnv* env = AndroidRuntime::getJNIEnv(); |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 143 | jint srcAddr = static_cast<jint>(message.initiator); |
| 144 | jint dstAddr = static_cast<jint>(message.destination); |
| 145 | jbyteArray body = env->NewByteArray(message.body.size()); |
| 146 | const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body.data()); |
| 147 | env->SetByteArrayRegion(body, 0, message.body.size(), bodyPtr); |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 148 | env->CallVoidMethod(mController->getCallbacksObj(), |
| 149 | gHdmiCecControllerClassInfo.handleIncomingCecCommand, srcAddr, |
| 150 | dstAddr, body); |
| 151 | env->DeleteLocalRef(body); |
| 152 | |
| 153 | checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| 154 | } |
| 155 | |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 156 | void propagateHotplugEvent(const HotplugEvent& event) { |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 157 | // Note that this method should be called in service thread. |
| 158 | JNIEnv* env = AndroidRuntime::getJNIEnv(); |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 159 | jint port = static_cast<jint>(event.portId); |
Jungshik Jang | 4223072 | 2014-07-07 17:40:25 +0900 | [diff] [blame] | 160 | jboolean connected = (jboolean) event.connected; |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 161 | env->CallVoidMethod(mController->getCallbacksObj(), |
Jungshik Jang | 4223072 | 2014-07-07 17:40:25 +0900 | [diff] [blame] | 162 | gHdmiCecControllerClassInfo.handleHotplug, port, connected); |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 163 | |
| 164 | checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| 165 | } |
| 166 | |
| 167 | // static |
| 168 | static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { |
| 169 | if (env->ExceptionCheck()) { |
| 170 | ALOGE("An exception was thrown by callback '%s'.", methodName); |
| 171 | LOGE_EX(env); |
| 172 | env->ExceptionClear(); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | HdmiCecController* mController; |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 177 | CecMessage mCecMessage; |
| 178 | HotplugEvent mHotplugEvent; |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 179 | }; |
| 180 | |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 181 | HdmiCecController::HdmiCecController(sp<IHdmiCec> hdmiCec, |
| 182 | jobject callbacksObj, const sp<Looper>& looper) |
| 183 | : mHdmiCec(hdmiCec), |
| 184 | mCallbacksObj(callbacksObj), |
| 185 | mLooper(looper) { |
| 186 | mHdmiCecCallback = new HdmiCecCallback(this); |
| 187 | Return<void> ret = mHdmiCec->setCallback(mHdmiCecCallback); |
Steven Moreland | d002a8b | 2017-01-03 17:18:24 -0800 | [diff] [blame] | 188 | if (!ret.isOk()) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 189 | ALOGE("Failed to set a cec callback."); |
| 190 | } |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 191 | } |
| 192 | |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 193 | HdmiCecController::~HdmiCecController() { |
| 194 | Return<void> ret = mHdmiCec->setCallback(nullptr); |
Steven Moreland | d002a8b | 2017-01-03 17:18:24 -0800 | [diff] [blame] | 195 | if (!ret.isOk()) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 196 | ALOGE("Failed to set a cec callback."); |
| 197 | } |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 198 | } |
| 199 | |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 200 | int HdmiCecController::sendMessage(const CecMessage& message) { |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 201 | // TODO: propagate send_message's return value. |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 202 | Return<SendMessageResult> ret = mHdmiCec->sendMessage(message); |
Steven Moreland | d002a8b | 2017-01-03 17:18:24 -0800 | [diff] [blame] | 203 | if (!ret.isOk()) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 204 | ALOGE("Failed to send CEC message."); |
| 205 | return static_cast<int>(SendMessageResult::FAIL); |
| 206 | } |
| 207 | return static_cast<int>((SendMessageResult) ret); |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 208 | } |
| 209 | |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 210 | int HdmiCecController::addLogicalAddress(CecLogicalAddress address) { |
| 211 | Return<Result> ret = mHdmiCec->addLogicalAddress(address); |
Steven Moreland | d002a8b | 2017-01-03 17:18:24 -0800 | [diff] [blame] | 212 | if (!ret.isOk()) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 213 | ALOGE("Failed to add a logical address."); |
| 214 | return static_cast<int>(Result::FAILURE_UNKNOWN); |
| 215 | } |
| 216 | return static_cast<int>((Result) ret); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 217 | } |
| 218 | |
| 219 | void HdmiCecController::clearLogicaladdress() { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 220 | Return<void> ret = mHdmiCec->clearLogicalAddress(); |
Steven Moreland | d002a8b | 2017-01-03 17:18:24 -0800 | [diff] [blame] | 221 | if (!ret.isOk()) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 222 | ALOGE("Failed to clear logical address."); |
| 223 | } |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 224 | } |
| 225 | |
| 226 | int HdmiCecController::getPhysicalAddress() { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 227 | Result result; |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 228 | uint16_t addr; |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 229 | Return<void> ret = mHdmiCec->getPhysicalAddress([&result, &addr](Result res, uint16_t paddr) { |
| 230 | result = res; |
| 231 | addr = paddr; |
| 232 | }); |
Steven Moreland | d002a8b | 2017-01-03 17:18:24 -0800 | [diff] [blame] | 233 | if (!ret.isOk()) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 234 | ALOGE("Failed to get physical address."); |
| 235 | return INVALID_PHYSICAL_ADDRESS; |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 236 | } |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 237 | return result == Result::SUCCESS ? addr : INVALID_PHYSICAL_ADDRESS; |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 238 | } |
| 239 | |
| 240 | int HdmiCecController::getVersion() { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 241 | Return<int32_t> ret = mHdmiCec->getCecVersion(); |
Steven Moreland | d002a8b | 2017-01-03 17:18:24 -0800 | [diff] [blame] | 242 | if (!ret.isOk()) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 243 | ALOGE("Failed to get cec version."); |
| 244 | } |
| 245 | return ret; |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 246 | } |
| 247 | |
| 248 | uint32_t HdmiCecController::getVendorId() { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 249 | Return<uint32_t> ret = mHdmiCec->getVendorId(); |
Steven Moreland | d002a8b | 2017-01-03 17:18:24 -0800 | [diff] [blame] | 250 | if (!ret.isOk()) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 251 | ALOGE("Failed to get vendor id."); |
| 252 | } |
| 253 | return ret; |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 254 | } |
| 255 | |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 256 | jobjectArray HdmiCecController::getPortInfos() { |
| 257 | JNIEnv* env = AndroidRuntime::getJNIEnv(); |
Jinsuk Kim | 63dd3bb | 2014-06-13 14:46:17 +0900 | [diff] [blame] | 258 | jclass hdmiPortInfo = env->FindClass("android/hardware/hdmi/HdmiPortInfo"); |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 259 | if (hdmiPortInfo == NULL) { |
| 260 | return NULL; |
| 261 | } |
| 262 | jmethodID ctor = env->GetMethodID(hdmiPortInfo, "<init>", "(IIIZZZ)V"); |
| 263 | if (ctor == NULL) { |
| 264 | return NULL; |
| 265 | } |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 266 | hidl_vec<HdmiPortInfo> ports; |
| 267 | Return<void> ret = mHdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) { |
| 268 | ports = list; |
| 269 | }); |
Steven Moreland | d002a8b | 2017-01-03 17:18:24 -0800 | [diff] [blame] | 270 | if (!ret.isOk()) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 271 | ALOGE("Failed to get port information."); |
| 272 | return NULL; |
| 273 | } |
| 274 | jobjectArray res = env->NewObjectArray(ports.size(), hdmiPortInfo, NULL); |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 275 | |
| 276 | // MHL support field will be obtained from MHL HAL. Leave it to false. |
| 277 | jboolean mhlSupported = (jboolean) 0; |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 278 | for (size_t i = 0; i < ports.size(); ++i) { |
| 279 | jboolean cecSupported = (jboolean) ports[i].cecSupported; |
| 280 | jboolean arcSupported = (jboolean) ports[i].arcSupported; |
| 281 | jobject infoObj = env->NewObject(hdmiPortInfo, ctor, ports[i].portId, ports[i].type, |
| 282 | ports[i].physicalAddress, cecSupported, mhlSupported, arcSupported); |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 283 | env->SetObjectArrayElement(res, i, infoObj); |
| 284 | } |
| 285 | return res; |
| 286 | } |
| 287 | |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 288 | void HdmiCecController::setOption(OptionKey key, bool enabled) { |
| 289 | Return<void> ret = mHdmiCec->setOption(key, enabled); |
Steven Moreland | d002a8b | 2017-01-03 17:18:24 -0800 | [diff] [blame] | 290 | if (!ret.isOk()) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 291 | ALOGE("Failed to set option."); |
| 292 | } |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 293 | } |
| 294 | |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 295 | void HdmiCecController::setLanguage(hidl_string language) { |
| 296 | Return<void> ret = mHdmiCec->setLanguage(language); |
Steven Moreland | d002a8b | 2017-01-03 17:18:24 -0800 | [diff] [blame] | 297 | if (!ret.isOk()) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 298 | ALOGE("Failed to set language."); |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | // Enable audio return channel. |
| 303 | void HdmiCecController::enableAudioReturnChannel(int port, bool enabled) { |
| 304 | Return<void> ret = mHdmiCec->enableAudioReturnChannel(port, enabled); |
Steven Moreland | d002a8b | 2017-01-03 17:18:24 -0800 | [diff] [blame] | 305 | if (!ret.isOk()) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 306 | ALOGE("Failed to enable/disable ARC."); |
| 307 | } |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 308 | } |
| 309 | |
| 310 | // Whether to hdmi device is connected to the given port. |
| 311 | bool HdmiCecController::isConnected(int port) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 312 | Return<bool> ret = mHdmiCec->isConnected(port); |
Steven Moreland | d002a8b | 2017-01-03 17:18:24 -0800 | [diff] [blame] | 313 | if (!ret.isOk()) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 314 | ALOGE("Failed to get connection info."); |
| 315 | } |
| 316 | return ret; |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 317 | } |
| 318 | |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 319 | Return<void> HdmiCecController::HdmiCecCallback::onCecMessage(const CecMessage& message) { |
| 320 | sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(mController, message)); |
| 321 | mController->mLooper->sendMessage(handler, HdmiCecEventHandler::EventType::CEC_MESSAGE); |
| 322 | return Void(); |
| 323 | } |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 324 | |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 325 | Return<void> HdmiCecController::HdmiCecCallback::onHotplugEvent(const HotplugEvent& event) { |
| 326 | sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(mController, event)); |
| 327 | mController->mLooper->sendMessage(handler, HdmiCecEventHandler::EventType::HOT_PLUG); |
| 328 | return Void(); |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 329 | } |
| 330 | |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 331 | //------------------------------------------------------------------------------ |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 332 | #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ |
| 333 | var = env->GetMethodID(clazz, methodName, methodDescriptor); \ |
Chih-Hung Hsieh | 6c89616 | 2016-05-19 15:29:38 -0700 | [diff] [blame] | 334 | LOG_FATAL_IF(! (var), "Unable to find method " methodName); |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 335 | |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 336 | static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj, |
| 337 | jobject messageQueueObj) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 338 | // TODO(b/31632518) |
Chris Phoenix | 7e6627e | 2017-01-20 18:42:41 -0800 | [diff] [blame] | 339 | sp<IHdmiCec> hdmiCec = IHdmiCec::getService(); |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 340 | if (hdmiCec == nullptr) { |
| 341 | ALOGE("Couldn't get tv.cec service."); |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 342 | return 0; |
| 343 | } |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 344 | sp<MessageQueue> messageQueue = |
| 345 | android_os_MessageQueue_getMessageQueue(env, messageQueueObj); |
| 346 | |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 347 | HdmiCecController* controller = new HdmiCecController( |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 348 | hdmiCec, |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 349 | env->NewGlobalRef(callbacksObj), |
| 350 | messageQueue->getLooper()); |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 351 | |
| 352 | GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz, |
| 353 | "handleIncomingCecCommand", "(II[B)V"); |
| 354 | GET_METHOD_ID(gHdmiCecControllerClassInfo.handleHotplug, clazz, |
Jungshik Jang | 4223072 | 2014-07-07 17:40:25 +0900 | [diff] [blame] | 355 | "handleHotplug", "(IZ)V"); |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 356 | |
| 357 | return reinterpret_cast<jlong>(controller); |
| 358 | } |
| 359 | |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 360 | static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr, |
| 361 | jint srcAddr, jint dstAddr, jbyteArray body) { |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 362 | CecMessage message; |
| 363 | message.initiator = static_cast<CecLogicalAddress>(srcAddr); |
| 364 | message.destination = static_cast<CecLogicalAddress>(dstAddr); |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 365 | |
| 366 | jsize len = env->GetArrayLength(body); |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 367 | ScopedByteArrayRO bodyPtr(env, body); |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 368 | size_t bodyLength = MIN(static_cast<size_t>(len), |
| 369 | static_cast<size_t>(MaxLength::MESSAGE_BODY)); |
| 370 | message.body.resize(bodyLength); |
| 371 | for (size_t i = 0; i < bodyLength; ++i) { |
| 372 | message.body[i] = static_cast<uint8_t>(bodyPtr[i]); |
| 373 | } |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 374 | |
| 375 | HdmiCecController* controller = |
| 376 | reinterpret_cast<HdmiCecController*>(controllerPtr); |
| 377 | return controller->sendMessage(message); |
| 378 | } |
| 379 | |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 380 | static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr, |
| 381 | jint logicalAddress) { |
| 382 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 383 | return controller->addLogicalAddress(static_cast<CecLogicalAddress>(logicalAddress)); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 384 | } |
| 385 | |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 386 | static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) { |
| 387 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 388 | controller->clearLogicaladdress(); |
| 389 | } |
| 390 | |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 391 | static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) { |
| 392 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 393 | return controller->getPhysicalAddress(); |
| 394 | } |
| 395 | |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 396 | static jint nativeGetVersion(JNIEnv* env, jclass clazz, jlong controllerPtr) { |
| 397 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 398 | return controller->getVersion(); |
| 399 | } |
| 400 | |
| 401 | static jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) { |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 402 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 403 | return controller->getVendorId(); |
| 404 | } |
| 405 | |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 406 | static jobjectArray nativeGetPortInfos(JNIEnv* env, jclass clazz, jlong controllerPtr) { |
| 407 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
| 408 | return controller->getPortInfos(); |
| 409 | } |
| 410 | |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 411 | static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) { |
| 412 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 413 | controller->setOption(static_cast<OptionKey>(flag), value > 0 ? true : false); |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 414 | } |
| 415 | |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 416 | static void nativeSetLanguage(JNIEnv* env, jclass clazz, jlong controllerPtr, jstring language) { |
| 417 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
| 418 | const char *languageStr = env->GetStringUTFChars(language, NULL); |
| 419 | controller->setLanguage(languageStr); |
| 420 | env->ReleaseStringUTFChars(language, languageStr); |
| 421 | } |
| 422 | |
| 423 | static void nativeEnableAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr, |
Jinsuk Kim | 1481a42 | 2014-12-17 16:15:05 +0900 | [diff] [blame] | 424 | jint port, jboolean enabled) { |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 425 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 426 | controller->enableAudioReturnChannel(port, enabled == JNI_TRUE); |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 427 | } |
| 428 | |
| 429 | static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) { |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 430 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 431 | return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ; |
| 432 | } |
| 433 | |
Daniel Micay | 76f6a86 | 2015-09-19 17:31:01 -0400 | [diff] [blame] | 434 | static const JNINativeMethod sMethods[] = { |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 435 | /* name, signature, funcPtr */ |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 436 | { "nativeInit", |
| 437 | "(Lcom/android/server/hdmi/HdmiCecController;Landroid/os/MessageQueue;)J", |
| 438 | (void *) nativeInit }, |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 439 | { "nativeSendCecCommand", "(JII[B)I", (void *) nativeSendCecCommand }, |
| 440 | { "nativeAddLogicalAddress", "(JI)I", (void *) nativeAddLogicalAddress }, |
| 441 | { "nativeClearLogicalAddress", "(J)V", (void *) nativeClearLogicalAddress }, |
| 442 | { "nativeGetPhysicalAddress", "(J)I", (void *) nativeGetPhysicalAddress }, |
| 443 | { "nativeGetVersion", "(J)I", (void *) nativeGetVersion }, |
| 444 | { "nativeGetVendorId", "(J)I", (void *) nativeGetVendorId }, |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 445 | { "nativeGetPortInfos", |
Jinsuk Kim | 63dd3bb | 2014-06-13 14:46:17 +0900 | [diff] [blame] | 446 | "(J)[Landroid/hardware/hdmi/HdmiPortInfo;", |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 447 | (void *) nativeGetPortInfos }, |
Donghyun Cho | bc6e372 | 2016-11-04 05:25:52 +0900 | [diff] [blame] | 448 | { "nativeSetOption", "(JIZ)V", (void *) nativeSetOption }, |
| 449 | { "nativeSetLanguage", "(JLjava/lang/String;)V", (void *) nativeSetLanguage }, |
| 450 | { "nativeEnableAudioReturnChannel", "(JIZ)V", (void *) nativeEnableAudioReturnChannel }, |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 451 | { "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected }, |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 452 | }; |
| 453 | |
| 454 | #define CLASS_PATH "com/android/server/hdmi/HdmiCecController" |
| 455 | |
| 456 | int register_android_server_hdmi_HdmiCecController(JNIEnv* env) { |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 457 | int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods)); |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 458 | LOG_FATAL_IF(res < 0, "Unable to register native methods."); |
Bernhard Rosenkränzer | 4048a4b | 2014-11-23 22:24:32 +0100 | [diff] [blame] | 459 | (void)res; // Don't scream about unused variable in the LOG_NDEBUG case |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 460 | return 0; |
| 461 | } |
| 462 | |
| 463 | } /* namespace android */ |