1 /*
2 * Copyright 2024 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 #include <memory>
18 #include <utility>
19 #define LOG_TAG "ASurfaceControlInputReceiverTest"
20
21 #include <android/choreographer.h>
22 #include <android/input.h>
23 #include <android/input_transfer_token_jni.h>
24 #include <android/log.h>
25 #include <android/looper.h>
26 #include <android/surface_control.h>
27 #include <android/surface_control_input_receiver.h>
28 #include <android/surface_control_jni.h>
29 #include <jni.h>
30 #include <nativehelper/JNIHelp.h>
31 #include <nativehelper/scoped_local_ref.h>
32
33 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
34
35 namespace {
36 static struct {
37 jmethodID onMotionEvent;
38 jmethodID onKeyEvent;
39 } gInputReceiver;
40
41 class InputReceiverCallbackWrapper {
42 public:
InputReceiverCallbackWrapper(JNIEnv * env,jobject object)43 explicit InputReceiverCallbackWrapper(JNIEnv* env, jobject object) {
44 env->GetJavaVM(&mVm);
45 mInputReceiverObj = env->NewGlobalRef(object);
46 mAInputReceiverCallbacks = AInputReceiverCallbacks_create(this);
47 AInputReceiverCallbacks_setKeyEventCallback(mAInputReceiverCallbacks, onKeyEventThunk);
48 AInputReceiverCallbacks_setMotionEventCallback(mAInputReceiverCallbacks,
49 onMotionEventThunk);
50 }
51
onKeyEvent(AInputEvent * inputEvent)52 bool onKeyEvent(AInputEvent* inputEvent) {
53 JNIEnv* env = getenv();
54 ScopedLocalRef<jobject> event(env, AInputEvent_toJava(env, inputEvent));
55 AInputEvent_release(inputEvent);
56 return env->CallBooleanMethod(mInputReceiverObj, gInputReceiver.onKeyEvent, event.get());
57 }
58
onMotionEvent(AInputEvent * inputEvent)59 bool onMotionEvent(AInputEvent* inputEvent) {
60 JNIEnv* env = getenv();
61 ScopedLocalRef<jobject> event(env, AInputEvent_toJava(env, inputEvent));
62 AInputEvent_release(inputEvent);
63 return env->CallBooleanMethod(mInputReceiverObj, gInputReceiver.onMotionEvent, event.get());
64 }
65
onKeyEventThunk(void * context,AInputEvent * inputEvent)66 static bool onKeyEventThunk(void* context, AInputEvent* inputEvent) {
67 InputReceiverCallbackWrapper* listener =
68 reinterpret_cast<InputReceiverCallbackWrapper*>(context);
69 return listener->onKeyEvent(inputEvent);
70 }
71
onMotionEventThunk(void * context,AInputEvent * inputEvent)72 static bool onMotionEventThunk(void* context, AInputEvent* inputEvent) {
73 InputReceiverCallbackWrapper* listener =
74 reinterpret_cast<InputReceiverCallbackWrapper*>(context);
75 return listener->onMotionEvent(inputEvent);
76 }
77
getAInputReceiverCallbacks()78 AInputReceiverCallbacks* getAInputReceiverCallbacks() { return mAInputReceiverCallbacks; }
79
~InputReceiverCallbackWrapper()80 ~InputReceiverCallbackWrapper() {
81 getenv()->DeleteGlobalRef(mInputReceiverObj);
82 AInputReceiverCallbacks_release(mAInputReceiverCallbacks);
83 }
84
85 private:
getenv()86 JNIEnv* getenv() {
87 JNIEnv* env;
88 mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
89 return env;
90 }
91
92 jobject mInputReceiverObj;
93 JavaVM* mVm;
94 AInputReceiverCallbacks* mAInputReceiverCallbacks;
95 };
96
97 class InputReceiverWrapper {
98 public:
InputReceiverWrapper(AInputReceiver * aInputReceiver,std::unique_ptr<InputReceiverCallbackWrapper> callback)99 InputReceiverWrapper(AInputReceiver* aInputReceiver,
100 std::unique_ptr<InputReceiverCallbackWrapper> callback)
101 : mInputReceiver(aInputReceiver), mInputReceiverCallbackWrapper(std::move(callback)) {}
102
~InputReceiverWrapper()103 ~InputReceiverWrapper() { AInputReceiver_release(mInputReceiver); }
104 AInputReceiver* mInputReceiver;
105
106 private:
107 std::unique_ptr<InputReceiverCallbackWrapper> mInputReceiverCallbackWrapper;
108 };
109
nativeCreateInputReceiver(JNIEnv * env,jclass,jboolean batched,jobject hostInputTransferTokenObj,jlong surfaceControlObj,jobject inputReceiverObj)110 static jlong nativeCreateInputReceiver(JNIEnv* env, jclass, jboolean batched,
111 jobject hostInputTransferTokenObj, jlong surfaceControlObj,
112 jobject inputReceiverObj) {
113 AInputTransferToken* hostTransferToken =
114 AInputTransferToken_fromJava(env, hostInputTransferTokenObj);
115 ASurfaceControl* aSurfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControlObj);
116
117 std::unique_ptr<InputReceiverCallbackWrapper> callbackWrapper =
118 std::make_unique<InputReceiverCallbackWrapper>(env, inputReceiverObj);
119
120 AInputReceiver* receiver;
121 ALooper* looper = ALooper_prepare(0);
122
123 if (batched) {
124 AChoreographer* choreographer = AChoreographer_getInstance();
125 receiver =
126 AInputReceiver_createBatchedInputReceiver(choreographer, hostTransferToken,
127 aSurfaceControl,
128 callbackWrapper
129 ->getAInputReceiverCallbacks());
130 } else {
131 receiver =
132 AInputReceiver_createUnbatchedInputReceiver(looper, hostTransferToken,
133 aSurfaceControl,
134 callbackWrapper
135 ->getAInputReceiverCallbacks());
136 }
137
138 InputReceiverWrapper* inputReceiverWrapper =
139 new InputReceiverWrapper(receiver, std::move(callbackWrapper));
140 return reinterpret_cast<jlong>(inputReceiverWrapper);
141 }
142
nativeDeleteInputReceiver(JNIEnv *,jclass,jlong receiverObj)143 static void nativeDeleteInputReceiver(JNIEnv*, jclass, jlong receiverObj) {
144 InputReceiverWrapper* receiver = reinterpret_cast<InputReceiverWrapper*>(receiverObj);
145 delete receiver;
146 }
147
nativeGetInputTransferToken(JNIEnv * env,jclass,jlong receiverObj)148 static jobject nativeGetInputTransferToken(JNIEnv* env, jclass, jlong receiverObj) {
149 InputReceiverWrapper* receiver = reinterpret_cast<InputReceiverWrapper*>(receiverObj);
150 return AInputTransferToken_toJava(env,
151 AInputReceiver_getInputTransferToken(
152 receiver->mInputReceiver));
153 }
154
155 static const JNINativeMethod sMethods[] = {
156 // clang-format off
157 {"nCreateInputReceiver",
158 "(ZLandroid/window/InputTransferToken;JLandroid/view/cts/util/ASurfaceControlInputReceiverTestUtils$InputReceiver;)J",
159 (void *) nativeCreateInputReceiver},
160 {"nDeleteInputReceiver", "(J)V", (void *) nativeDeleteInputReceiver},
161 {"nGetInputTransferToken", "(J)Landroid/window/InputTransferToken;", (void*) nativeGetInputTransferToken},
162 // clang-format on
163 };
164
165 } // anonymous namespace
166
register_android_window_cts_ASurfaceControlInputReceiverTest(JNIEnv * env)167 jint register_android_window_cts_ASurfaceControlInputReceiverTest(JNIEnv* env) {
168 jclass clazz = env->FindClass("android/view/cts/util/ASurfaceControlInputReceiverTestUtils");
169 int err = env->RegisterNatives(clazz, sMethods, NELEM(sMethods));
170
171 jclass inputReceiver = env->FindClass(
172 "android/view/cts/util/ASurfaceControlInputReceiverTestUtils$InputReceiver");
173 gInputReceiver.onMotionEvent =
174 env->GetMethodID(inputReceiver, "onMotionEvent", "(Landroid/view/MotionEvent;)Z");
175 gInputReceiver.onKeyEvent =
176 env->GetMethodID(inputReceiver, "onKeyEvent", "(Landroid/view/KeyEvent;)Z");
177 return err;
178 }
179