blob: c22109c7816a2546e9b979a07fa06fc97d7030e4 [file] [log] [blame]
Jungshik Jang0792d372014-04-23 17:57:26 +09001/*
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 Moreland2279b252017-07-19 09:50:45 -070021#include <nativehelper/JNIHelp.h>
22#include <nativehelper/ScopedPrimitiveArray.h>
Jungshik Jange9c77c82014-04-24 20:30:09 +090023
Donghyun Chobc6e3722016-11-04 05:25:52 +090024#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 Jang4085d0e2014-05-27 19:52:39 +090027#include <android_os_MessageQueue.h>
Jungshik Jang0792d372014-04-23 17:57:26 +090028#include <android_runtime/AndroidRuntime.h>
29#include <android_runtime/Log.h>
Jungshik Jange9c77c82014-04-24 20:30:09 +090030#include <sys/param.h>
Donghyun Chobc6e3722016-11-04 05:25:52 +090031#include <utils/Errors.h>
Jungshik Jang4085d0e2014-05-27 19:52:39 +090032#include <utils/Looper.h>
33#include <utils/RefBase.h>
Jungshik Jang0792d372014-04-23 17:57:26 +090034
Donghyun Chobc6e3722016-11-04 05:25:52 +090035using ::android::hardware::tv::cec::V1_0::CecLogicalAddress;
36using ::android::hardware::tv::cec::V1_0::CecMessage;
37using ::android::hardware::tv::cec::V1_0::HdmiPortInfo;
38using ::android::hardware::tv::cec::V1_0::HotplugEvent;
39using ::android::hardware::tv::cec::V1_0::IHdmiCec;
40using ::android::hardware::tv::cec::V1_0::IHdmiCecCallback;
41using ::android::hardware::tv::cec::V1_0::MaxLength;
42using ::android::hardware::tv::cec::V1_0::OptionKey;
43using ::android::hardware::tv::cec::V1_0::Result;
44using ::android::hardware::tv::cec::V1_0::SendMessageResult;
45using ::android::hardware::Return;
46using ::android::hardware::Void;
47using ::android::hardware::hidl_vec;
48using ::android::hardware::hidl_string;
49
Jungshik Jang0792d372014-04-23 17:57:26 +090050namespace android {
51
52static struct {
Jungshik Jange9c77c82014-04-24 20:30:09 +090053 jmethodID handleIncomingCecCommand;
54 jmethodID handleHotplug;
Jungshik Jang0792d372014-04-23 17:57:26 +090055} gHdmiCecControllerClassInfo;
56
Jungshik Jang0792d372014-04-23 17:57:26 +090057class HdmiCecController {
58public:
Donghyun Chobc6e3722016-11-04 05:25:52 +090059 HdmiCecController(sp<IHdmiCec> hdmiCec, jobject callbacksObj, const sp<Looper>& looper);
60 ~HdmiCecController();
Jungshik Jange9c77c82014-04-24 20:30:09 +090061
62 // Send message to other device. Note that it runs in IO thread.
Donghyun Chobc6e3722016-11-04 05:25:52 +090063 int sendMessage(const CecMessage& message);
Jungshik Janga9095ba2014-05-02 13:06:22 +090064 // Add a logical address to device.
Donghyun Chobc6e3722016-11-04 05:25:52 +090065 int addLogicalAddress(CecLogicalAddress address);
Jungshik Janga9095ba2014-05-02 13:06:22 +090066 // 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 Kim0340bbc2014-06-05 11:07:47 +090074 // Get Port information on all the HDMI ports.
75 jobjectArray getPortInfos();
Donghyun Chobc6e3722016-11-04 05:25:52 +090076 // 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 Jang092b4452014-06-11 15:19:17 +090082 // Whether to hdmi device is connected to the given port.
83 bool isConnected(int port);
Jungshik Jang0792d372014-04-23 17:57:26 +090084
Jungshik Jang4085d0e2014-05-27 19:52:39 +090085 jobject getCallbacksObj() const {
86 return mCallbacksObj;
87 }
Jungshik Jang0792d372014-04-23 17:57:26 +090088
Jungshik Jang4085d0e2014-05-27 19:52:39 +090089private:
Donghyun Chobc6e3722016-11-04 05:25:52 +090090 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 Kima6ce7702014-05-11 06:54:49 +090099 static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
Jungshik Jange9c77c82014-04-24 20:30:09 +0900100
Donghyun Chobc6e3722016-11-04 05:25:52 +0900101 sp<IHdmiCec> mHdmiCec;
Jungshik Jang0792d372014-04-23 17:57:26 +0900102 jobject mCallbacksObj;
Donghyun Chobc6e3722016-11-04 05:25:52 +0900103 sp<IHdmiCecCallback> mHdmiCecCallback;
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900104 sp<Looper> mLooper;
Jungshik Jang0792d372014-04-23 17:57:26 +0900105};
106
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900107// Handler class to delegate incoming message to service thread.
108class HdmiCecEventHandler : public MessageHandler {
109public:
Donghyun Chobc6e3722016-11-04 05:25:52 +0900110 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 Jang4085d0e2014-05-27 19:52:39 +0900122
123 virtual ~HdmiCecEventHandler() {}
124
125 void handleMessage(const Message& message) {
126 switch (message.what) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900127 case EventType::CEC_MESSAGE:
128 propagateCecCommand(mCecMessage);
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900129 break;
Donghyun Chobc6e3722016-11-04 05:25:52 +0900130 case EventType::HOT_PLUG:
131 propagateHotplugEvent(mHotplugEvent);
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900132 break;
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900133 default:
134 // TODO: add more type whenever new type is introduced.
135 break;
136 }
137 }
138
139private:
140 // Propagate the message up to Java layer.
Donghyun Chobc6e3722016-11-04 05:25:52 +0900141 void propagateCecCommand(const CecMessage& message) {
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900142 JNIEnv* env = AndroidRuntime::getJNIEnv();
Donghyun Chobc6e3722016-11-04 05:25:52 +0900143 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 Jang4085d0e2014-05-27 19:52:39 +0900148 env->CallVoidMethod(mController->getCallbacksObj(),
149 gHdmiCecControllerClassInfo.handleIncomingCecCommand, srcAddr,
150 dstAddr, body);
151 env->DeleteLocalRef(body);
152
153 checkAndClearExceptionFromCallback(env, __FUNCTION__);
154 }
155
Donghyun Chobc6e3722016-11-04 05:25:52 +0900156 void propagateHotplugEvent(const HotplugEvent& event) {
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900157 // Note that this method should be called in service thread.
158 JNIEnv* env = AndroidRuntime::getJNIEnv();
Donghyun Chobc6e3722016-11-04 05:25:52 +0900159 jint port = static_cast<jint>(event.portId);
Jungshik Jang42230722014-07-07 17:40:25 +0900160 jboolean connected = (jboolean) event.connected;
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900161 env->CallVoidMethod(mController->getCallbacksObj(),
Jungshik Jang42230722014-07-07 17:40:25 +0900162 gHdmiCecControllerClassInfo.handleHotplug, port, connected);
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900163
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 Chobc6e3722016-11-04 05:25:52 +0900177 CecMessage mCecMessage;
178 HotplugEvent mHotplugEvent;
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900179};
180
Donghyun Chobc6e3722016-11-04 05:25:52 +0900181HdmiCecController::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 Morelandd002a8b2017-01-03 17:18:24 -0800188 if (!ret.isOk()) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900189 ALOGE("Failed to set a cec callback.");
190 }
Jungshik Jang0792d372014-04-23 17:57:26 +0900191}
192
Donghyun Chobc6e3722016-11-04 05:25:52 +0900193HdmiCecController::~HdmiCecController() {
194 Return<void> ret = mHdmiCec->setCallback(nullptr);
Steven Morelandd002a8b2017-01-03 17:18:24 -0800195 if (!ret.isOk()) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900196 ALOGE("Failed to set a cec callback.");
197 }
Jungshik Jange9c77c82014-04-24 20:30:09 +0900198}
199
Donghyun Chobc6e3722016-11-04 05:25:52 +0900200int HdmiCecController::sendMessage(const CecMessage& message) {
Jungshik Jange9c77c82014-04-24 20:30:09 +0900201 // TODO: propagate send_message's return value.
Donghyun Chobc6e3722016-11-04 05:25:52 +0900202 Return<SendMessageResult> ret = mHdmiCec->sendMessage(message);
Steven Morelandd002a8b2017-01-03 17:18:24 -0800203 if (!ret.isOk()) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900204 ALOGE("Failed to send CEC message.");
205 return static_cast<int>(SendMessageResult::FAIL);
206 }
207 return static_cast<int>((SendMessageResult) ret);
Jungshik Jange9c77c82014-04-24 20:30:09 +0900208}
209
Donghyun Chobc6e3722016-11-04 05:25:52 +0900210int HdmiCecController::addLogicalAddress(CecLogicalAddress address) {
211 Return<Result> ret = mHdmiCec->addLogicalAddress(address);
Steven Morelandd002a8b2017-01-03 17:18:24 -0800212 if (!ret.isOk()) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900213 ALOGE("Failed to add a logical address.");
214 return static_cast<int>(Result::FAILURE_UNKNOWN);
215 }
216 return static_cast<int>((Result) ret);
Jungshik Janga9095ba2014-05-02 13:06:22 +0900217}
218
219void HdmiCecController::clearLogicaladdress() {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900220 Return<void> ret = mHdmiCec->clearLogicalAddress();
Steven Morelandd002a8b2017-01-03 17:18:24 -0800221 if (!ret.isOk()) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900222 ALOGE("Failed to clear logical address.");
223 }
Jungshik Janga9095ba2014-05-02 13:06:22 +0900224}
225
226int HdmiCecController::getPhysicalAddress() {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900227 Result result;
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900228 uint16_t addr;
Donghyun Chobc6e3722016-11-04 05:25:52 +0900229 Return<void> ret = mHdmiCec->getPhysicalAddress([&result, &addr](Result res, uint16_t paddr) {
230 result = res;
231 addr = paddr;
232 });
Steven Morelandd002a8b2017-01-03 17:18:24 -0800233 if (!ret.isOk()) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900234 ALOGE("Failed to get physical address.");
235 return INVALID_PHYSICAL_ADDRESS;
Jungshik Janga9095ba2014-05-02 13:06:22 +0900236 }
Donghyun Chobc6e3722016-11-04 05:25:52 +0900237 return result == Result::SUCCESS ? addr : INVALID_PHYSICAL_ADDRESS;
Jungshik Janga9095ba2014-05-02 13:06:22 +0900238}
239
240int HdmiCecController::getVersion() {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900241 Return<int32_t> ret = mHdmiCec->getCecVersion();
Steven Morelandd002a8b2017-01-03 17:18:24 -0800242 if (!ret.isOk()) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900243 ALOGE("Failed to get cec version.");
244 }
245 return ret;
Jungshik Janga9095ba2014-05-02 13:06:22 +0900246}
247
248uint32_t HdmiCecController::getVendorId() {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900249 Return<uint32_t> ret = mHdmiCec->getVendorId();
Steven Morelandd002a8b2017-01-03 17:18:24 -0800250 if (!ret.isOk()) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900251 ALOGE("Failed to get vendor id.");
252 }
253 return ret;
Jungshik Janga9095ba2014-05-02 13:06:22 +0900254}
255
Jinsuk Kim0340bbc2014-06-05 11:07:47 +0900256jobjectArray HdmiCecController::getPortInfos() {
257 JNIEnv* env = AndroidRuntime::getJNIEnv();
Jinsuk Kim63dd3bb2014-06-13 14:46:17 +0900258 jclass hdmiPortInfo = env->FindClass("android/hardware/hdmi/HdmiPortInfo");
Jinsuk Kim0340bbc2014-06-05 11:07:47 +0900259 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 Chobc6e3722016-11-04 05:25:52 +0900266 hidl_vec<HdmiPortInfo> ports;
267 Return<void> ret = mHdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) {
268 ports = list;
269 });
Steven Morelandd002a8b2017-01-03 17:18:24 -0800270 if (!ret.isOk()) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900271 ALOGE("Failed to get port information.");
272 return NULL;
273 }
274 jobjectArray res = env->NewObjectArray(ports.size(), hdmiPortInfo, NULL);
Jinsuk Kim0340bbc2014-06-05 11:07:47 +0900275
276 // MHL support field will be obtained from MHL HAL. Leave it to false.
277 jboolean mhlSupported = (jboolean) 0;
Donghyun Chobc6e3722016-11-04 05:25:52 +0900278 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 Kim0340bbc2014-06-05 11:07:47 +0900283 env->SetObjectArrayElement(res, i, infoObj);
284 }
285 return res;
286}
287
Donghyun Chobc6e3722016-11-04 05:25:52 +0900288void HdmiCecController::setOption(OptionKey key, bool enabled) {
289 Return<void> ret = mHdmiCec->setOption(key, enabled);
Steven Morelandd002a8b2017-01-03 17:18:24 -0800290 if (!ret.isOk()) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900291 ALOGE("Failed to set option.");
292 }
Jungshik Jang092b4452014-06-11 15:19:17 +0900293}
294
Donghyun Chobc6e3722016-11-04 05:25:52 +0900295void HdmiCecController::setLanguage(hidl_string language) {
296 Return<void> ret = mHdmiCec->setLanguage(language);
Steven Morelandd002a8b2017-01-03 17:18:24 -0800297 if (!ret.isOk()) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900298 ALOGE("Failed to set language.");
299 }
300}
301
302// Enable audio return channel.
303void HdmiCecController::enableAudioReturnChannel(int port, bool enabled) {
304 Return<void> ret = mHdmiCec->enableAudioReturnChannel(port, enabled);
Steven Morelandd002a8b2017-01-03 17:18:24 -0800305 if (!ret.isOk()) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900306 ALOGE("Failed to enable/disable ARC.");
307 }
Jungshik Jang092b4452014-06-11 15:19:17 +0900308}
309
310// Whether to hdmi device is connected to the given port.
311bool HdmiCecController::isConnected(int port) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900312 Return<bool> ret = mHdmiCec->isConnected(port);
Steven Morelandd002a8b2017-01-03 17:18:24 -0800313 if (!ret.isOk()) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900314 ALOGE("Failed to get connection info.");
315 }
316 return ret;
Jungshik Jang092b4452014-06-11 15:19:17 +0900317}
318
Donghyun Chobc6e3722016-11-04 05:25:52 +0900319Return<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 Jang0792d372014-04-23 17:57:26 +0900324
Donghyun Chobc6e3722016-11-04 05:25:52 +0900325Return<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 Jang0792d372014-04-23 17:57:26 +0900329}
330
Jungshik Jang0792d372014-04-23 17:57:26 +0900331//------------------------------------------------------------------------------
Jungshik Jange9c77c82014-04-24 20:30:09 +0900332#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
333 var = env->GetMethodID(clazz, methodName, methodDescriptor); \
Chih-Hung Hsieh6c896162016-05-19 15:29:38 -0700334 LOG_FATAL_IF(! (var), "Unable to find method " methodName);
Jungshik Jange9c77c82014-04-24 20:30:09 +0900335
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900336static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj,
337 jobject messageQueueObj) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900338 // TODO(b/31632518)
Chris Phoenix7e6627e2017-01-20 18:42:41 -0800339 sp<IHdmiCec> hdmiCec = IHdmiCec::getService();
Donghyun Chobc6e3722016-11-04 05:25:52 +0900340 if (hdmiCec == nullptr) {
341 ALOGE("Couldn't get tv.cec service.");
Jungshik Jange9c77c82014-04-24 20:30:09 +0900342 return 0;
343 }
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900344 sp<MessageQueue> messageQueue =
345 android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
346
Jungshik Jang0792d372014-04-23 17:57:26 +0900347 HdmiCecController* controller = new HdmiCecController(
Donghyun Chobc6e3722016-11-04 05:25:52 +0900348 hdmiCec,
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900349 env->NewGlobalRef(callbacksObj),
350 messageQueue->getLooper());
Jungshik Jange9c77c82014-04-24 20:30:09 +0900351
352 GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz,
353 "handleIncomingCecCommand", "(II[B)V");
354 GET_METHOD_ID(gHdmiCecControllerClassInfo.handleHotplug, clazz,
Jungshik Jang42230722014-07-07 17:40:25 +0900355 "handleHotplug", "(IZ)V");
Jungshik Jang0792d372014-04-23 17:57:26 +0900356
357 return reinterpret_cast<jlong>(controller);
358}
359
Jungshik Jange9c77c82014-04-24 20:30:09 +0900360static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr,
361 jint srcAddr, jint dstAddr, jbyteArray body) {
Donghyun Chobc6e3722016-11-04 05:25:52 +0900362 CecMessage message;
363 message.initiator = static_cast<CecLogicalAddress>(srcAddr);
364 message.destination = static_cast<CecLogicalAddress>(dstAddr);
Jungshik Jange9c77c82014-04-24 20:30:09 +0900365
366 jsize len = env->GetArrayLength(body);
Jungshik Jange9c77c82014-04-24 20:30:09 +0900367 ScopedByteArrayRO bodyPtr(env, body);
Donghyun Chobc6e3722016-11-04 05:25:52 +0900368 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 Jange9c77c82014-04-24 20:30:09 +0900374
375 HdmiCecController* controller =
376 reinterpret_cast<HdmiCecController*>(controllerPtr);
377 return controller->sendMessage(message);
378}
379
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900380static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr,
381 jint logicalAddress) {
382 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Donghyun Chobc6e3722016-11-04 05:25:52 +0900383 return controller->addLogicalAddress(static_cast<CecLogicalAddress>(logicalAddress));
Jungshik Janga9095ba2014-05-02 13:06:22 +0900384}
385
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900386static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
387 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Jungshik Janga9095ba2014-05-02 13:06:22 +0900388 controller->clearLogicaladdress();
389}
390
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900391static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
392 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Jungshik Janga9095ba2014-05-02 13:06:22 +0900393 return controller->getPhysicalAddress();
394}
395
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900396static jint nativeGetVersion(JNIEnv* env, jclass clazz, jlong controllerPtr) {
397 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Jungshik Janga9095ba2014-05-02 13:06:22 +0900398 return controller->getVersion();
399}
400
401static jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) {
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900402 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Jungshik Janga9095ba2014-05-02 13:06:22 +0900403 return controller->getVendorId();
404}
405
Jinsuk Kim0340bbc2014-06-05 11:07:47 +0900406static jobjectArray nativeGetPortInfos(JNIEnv* env, jclass clazz, jlong controllerPtr) {
407 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
408 return controller->getPortInfos();
409}
410
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900411static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) {
412 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Donghyun Chobc6e3722016-11-04 05:25:52 +0900413 controller->setOption(static_cast<OptionKey>(flag), value > 0 ? true : false);
Jungshik Jang092b4452014-06-11 15:19:17 +0900414}
415
Donghyun Chobc6e3722016-11-04 05:25:52 +0900416static 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
423static void nativeEnableAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
Jinsuk Kim1481a422014-12-17 16:15:05 +0900424 jint port, jboolean enabled) {
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900425 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Donghyun Chobc6e3722016-11-04 05:25:52 +0900426 controller->enableAudioReturnChannel(port, enabled == JNI_TRUE);
Jungshik Jang092b4452014-06-11 15:19:17 +0900427}
428
429static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) {
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900430 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Jungshik Jang092b4452014-06-11 15:19:17 +0900431 return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ;
432}
433
Daniel Micay76f6a862015-09-19 17:31:01 -0400434static const JNINativeMethod sMethods[] = {
Jungshik Jang0792d372014-04-23 17:57:26 +0900435 /* name, signature, funcPtr */
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900436 { "nativeInit",
437 "(Lcom/android/server/hdmi/HdmiCecController;Landroid/os/MessageQueue;)J",
438 (void *) nativeInit },
Jungshik Janga9095ba2014-05-02 13:06:22 +0900439 { "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 Kim0340bbc2014-06-05 11:07:47 +0900445 { "nativeGetPortInfos",
Jinsuk Kim63dd3bb2014-06-13 14:46:17 +0900446 "(J)[Landroid/hardware/hdmi/HdmiPortInfo;",
Jinsuk Kim0340bbc2014-06-05 11:07:47 +0900447 (void *) nativeGetPortInfos },
Donghyun Chobc6e3722016-11-04 05:25:52 +0900448 { "nativeSetOption", "(JIZ)V", (void *) nativeSetOption },
449 { "nativeSetLanguage", "(JLjava/lang/String;)V", (void *) nativeSetLanguage },
450 { "nativeEnableAudioReturnChannel", "(JIZ)V", (void *) nativeEnableAudioReturnChannel },
Jungshik Jang092b4452014-06-11 15:19:17 +0900451 { "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected },
Jungshik Jang0792d372014-04-23 17:57:26 +0900452};
453
454#define CLASS_PATH "com/android/server/hdmi/HdmiCecController"
455
456int register_android_server_hdmi_HdmiCecController(JNIEnv* env) {
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900457 int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods));
Jungshik Jang0792d372014-04-23 17:57:26 +0900458 LOG_FATAL_IF(res < 0, "Unable to register native methods.");
Bernhard Rosenkränzer4048a4b2014-11-23 22:24:32 +0100459 (void)res; // Don't scream about unused variable in the LOG_NDEBUG case
Jungshik Jang0792d372014-04-23 17:57:26 +0900460 return 0;
461}
462
463} /* namespace android */