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