Add surface_control_input_receiver native API

Bug: 324271765
Test: ASurfaceControlInputReceiverTest
Change-Id: Ia85a07af09878846c681e552c1f8471652f932fc
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 4812685..db3a67a 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -54,6 +54,7 @@
     srcs: [
         "activity_manager.cpp",
         "asset_manager.cpp",
+        "surface_control_input_receiver.cpp",
         "choreographer.cpp",
         "configuration.cpp",
         "hardware_buffer_jni.cpp",
diff --git a/native/android/input_transfer_token.cpp b/native/android/input_transfer_token.cpp
index 501e1d3..2e74aa3 100644
--- a/native/android/input_transfer_token.cpp
+++ b/native/android/input_transfer_token.cpp
@@ -25,7 +25,7 @@
 #define CHECK_NOT_NULL(name) \
     LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
 
-void InputTransferToken_acquire(InputTransferToken* inputTransferToken) {
+extern void InputTransferToken_acquire(InputTransferToken* inputTransferToken) {
     // incStrong/decStrong token must be the same, doesn't matter what it is
     inputTransferToken->incStrong((void*)InputTransferToken_acquire);
 }
@@ -52,7 +52,7 @@
     CHECK_NOT_NULL(aInputTransferToken);
     const InputTransferToken* inputTransferToken =
             reinterpret_cast<const InputTransferToken*>(aInputTransferToken);
-    return android_window_InputTransferToken_getJavaInputTransferToken(env, inputTransferToken);
+    return android_window_InputTransferToken_getJavaInputTransferToken(env, *inputTransferToken);
 }
 
 void AInputTransferToken_release(AInputTransferToken* aInputTransferToken) {
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index b2925bf..1c203e3 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -98,6 +98,14 @@
     AInputQueue_getEvent;
     AInputQueue_hasEvents;
     AInputQueue_preDispatchEvent;
+    AInputReceiver_createBatchedInputReceiver; # introduced=35
+    AInputReceiver_createUnbatchedInputReceiver; # introduced=35
+    AInputReceiver_release; # introduced=35
+    AInputReceiver_getInputTransferToken; # introduced=35
+    AInputReceiverCallbacks_create; # introduced=35
+    AInputReceiverCallbacks_release; # introduced=35
+    AInputReceiverCallbacks_setKeyEventCallback; # introduced=35
+    AInputReceiverCallbacks_setMotionEventCallback; # introduced=35
     AInputTransferToken_fromJava; # introduced=35
     AInputTransferToken_release; # introduced=35
     AInputTransferToken_toJava; # introduced=35
diff --git a/native/android/surface_control_input_receiver.cpp b/native/android/surface_control_input_receiver.cpp
new file mode 100644
index 0000000..da0defd
--- /dev/null
+++ b/native/android/surface_control_input_receiver.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/choreographer.h>
+#include <android/surface_control_input_receiver.h>
+#include <binder/Binder.h>
+#include <gui/Choreographer.h>
+#include <gui/InputTransferToken.h>
+#include <input/Input.h>
+#include <input/InputConsumerNoResampling.h>
+
+#include "android_view_WindowManagerGlobal.h"
+
+using namespace android;
+
+extern void InputTransferToken_acquire(InputTransferToken* inputTransferToken);
+
+struct AInputReceiverCallbacks {
+    AInputReceiverCallbacks(void* context) : context(context) {}
+    void* context;
+    AInputReceiver_onMotionEvent onMotionEvent = nullptr;
+    AInputReceiver_onKeyEvent onKeyEvent = nullptr;
+};
+
+class InputReceiver : public InputConsumerCallbacks {
+public:
+    InputReceiver(const sp<Looper>& looper, const std::shared_ptr<InputChannel>& inputChannel,
+                  const sp<IBinder>& clientToken, const sp<InputTransferToken>& inputTransferToken,
+                  AInputReceiverCallbacks* callbacks)
+          : mCallbacks(callbacks),
+            mInputConsumer(inputChannel, looper, *this),
+            mClientToken(clientToken),
+            mInputTransferToken(inputTransferToken) {}
+
+    ~InputReceiver() {
+        remove();
+    }
+
+    void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) override {
+        if (mCallbacks->onKeyEvent != nullptr) {
+            const bool handled = mCallbacks->onKeyEvent(mCallbacks->context,
+                                                        static_cast<AInputEvent*>(event.release()));
+            mInputConsumer.finishInputEvent(seq, handled);
+        }
+    }
+
+    void onMotionEvent(std::unique_ptr<MotionEvent> event, uint32_t seq) override {
+        if (mCallbacks->onMotionEvent != nullptr) {
+            const bool handled =
+                    mCallbacks->onMotionEvent(mCallbacks->context,
+                                              static_cast<AInputEvent*>(event.release()));
+            mInputConsumer.finishInputEvent(seq, handled);
+        }
+    }
+
+    void onFocusEvent(std::unique_ptr<FocusEvent>, uint32_t seq) override {
+        mInputConsumer.finishInputEvent(seq, false);
+    }
+    void onCaptureEvent(std::unique_ptr<CaptureEvent>, uint32_t seq) override {
+        mInputConsumer.finishInputEvent(seq, false);
+    }
+    void onDragEvent(std::unique_ptr<DragEvent>, uint32_t seq) override {
+        mInputConsumer.finishInputEvent(seq, false);
+    }
+    void onTouchModeEvent(std::unique_ptr<TouchModeEvent>, uint32_t seq) override {
+        mInputConsumer.finishInputEvent(seq, false);
+    }
+
+    virtual void onBatchedInputEventPending(int32_t) override {
+        mInputConsumer.consumeBatchedInputEvents(std::nullopt);
+    }
+
+    const AInputTransferToken* getInputTransferToken() {
+        InputTransferToken_acquire(mInputTransferToken.get());
+        return reinterpret_cast<const AInputTransferToken*>(mInputTransferToken.get());
+    }
+
+    void remove() {
+        removeInputChannel(mClientToken);
+    }
+
+    AInputReceiverCallbacks* mCallbacks;
+
+protected:
+    InputConsumerNoResampling mInputConsumer;
+
+private:
+    const sp<IBinder> mClientToken;
+    const sp<InputTransferToken> mInputTransferToken;
+};
+
+class BatchedInputReceiver : public InputReceiver {
+public:
+    BatchedInputReceiver(Choreographer& choreographer,
+                         const std::shared_ptr<InputChannel>& inputChannel,
+                         const sp<IBinder>& clientToken,
+                         const sp<InputTransferToken>& inputTransferToken,
+                         AInputReceiverCallbacks* callbacks)
+          : InputReceiver(choreographer.getLooper(), inputChannel, clientToken, inputTransferToken,
+                          callbacks),
+            mChoreographer(choreographer) {}
+
+    static void vsyncCallback(const AChoreographerFrameCallbackData* callbackData, void* data) {
+        BatchedInputReceiver* receiver = static_cast<BatchedInputReceiver*>(data);
+        receiver->onVsyncCallback(callbackData);
+    }
+
+    void onVsyncCallback(const AChoreographerFrameCallbackData* callbackData) {
+        int64_t frameTimeNanos = AChoreographerFrameCallbackData_getFrameTimeNanos(callbackData);
+        mInputConsumer.consumeBatchedInputEvents(frameTimeNanos);
+        mBatchedInputScheduled = false;
+    }
+
+    void onBatchedInputEventPending(int32_t) override {
+        scheduleBatchedInput();
+    }
+
+private:
+    Choreographer& mChoreographer;
+    bool mBatchedInputScheduled = false;
+
+    void scheduleBatchedInput() {
+        if (!mBatchedInputScheduled) {
+            mBatchedInputScheduled = true;
+            mChoreographer.postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, this, 0,
+                                                    CallbackType::CALLBACK_INPUT);
+        }
+    }
+};
+
+static inline AInputReceiver* InputReceiver_to_AInputReceiver(InputReceiver* inputReceiver) {
+    return reinterpret_cast<AInputReceiver*>(inputReceiver);
+}
+
+static inline InputReceiver* AInputReceiver_to_InputReceiver(AInputReceiver* aInputReceiver) {
+    return reinterpret_cast<InputReceiver*>(aInputReceiver);
+}
+
+AInputReceiver* AInputReceiver_createBatchedInputReceiver(AChoreographer* aChoreographer,
+                                                          const AInputTransferToken* hostToken,
+                                                          const ASurfaceControl* aSurfaceControl,
+                                                          AInputReceiverCallbacks* callbacks) {
+    // create input channel here through WMS
+    sp<IBinder> clientToken = sp<BBinder>::make();
+    sp<InputTransferToken> clientInputTransferToken = sp<InputTransferToken>::make();
+
+    std::shared_ptr<InputChannel> inputChannel =
+            createInputChannel(clientToken, reinterpret_cast<const InputTransferToken&>(*hostToken),
+                               reinterpret_cast<const SurfaceControl&>(*aSurfaceControl),
+                               *clientInputTransferToken);
+    return InputReceiver_to_AInputReceiver(
+            new BatchedInputReceiver(reinterpret_cast<Choreographer&>(*aChoreographer),
+                                     inputChannel, clientToken, clientInputTransferToken,
+                                     callbacks));
+}
+
+AInputReceiver* AInputReceiver_createUnbatchedInputReceiver(ALooper* aLooper,
+                                                            const AInputTransferToken* hostToken,
+                                                            const ASurfaceControl* aSurfaceControl,
+                                                            AInputReceiverCallbacks* callbacks) {
+    // create input channel here through WMS
+    sp<IBinder> clientToken = sp<BBinder>::make();
+    sp<InputTransferToken> clientInputTransferToken = sp<InputTransferToken>::make();
+
+    std::shared_ptr<InputChannel> inputChannel =
+            createInputChannel(clientToken, reinterpret_cast<const InputTransferToken&>(*hostToken),
+                               reinterpret_cast<const SurfaceControl&>(*aSurfaceControl),
+                               *clientInputTransferToken);
+    return InputReceiver_to_AInputReceiver(new InputReceiver(reinterpret_cast<Looper*>(aLooper),
+                                                             inputChannel, clientToken,
+                                                             clientInputTransferToken, callbacks));
+}
+
+const AInputTransferToken* AInputReceiver_getInputTransferToken(AInputReceiver* aInputReceiver) {
+    return AInputReceiver_to_InputReceiver(aInputReceiver)->getInputTransferToken();
+}
+
+void AInputReceiver_release(AInputReceiver* aInputReceiver) {
+    InputReceiver* inputReceiver = AInputReceiver_to_InputReceiver(aInputReceiver);
+    inputReceiver->remove();
+    delete inputReceiver;
+}
+
+void AInputReceiverCallbacks_setMotionEventCallback(AInputReceiverCallbacks* callbacks,
+                                                    AInputReceiver_onMotionEvent onMotionEvent) {
+    callbacks->onMotionEvent = onMotionEvent;
+}
+
+void AInputReceiverCallbacks_setKeyEventCallback(AInputReceiverCallbacks* callbacks,
+                                                 AInputReceiver_onKeyEvent onKeyEvent) {
+    callbacks->onKeyEvent = onKeyEvent;
+}
+
+AInputReceiverCallbacks* AInputReceiverCallbacks_create(void* context) {
+    return new AInputReceiverCallbacks(context);
+}
+
+void AInputReceiverCallbacks_release(AInputReceiverCallbacks* callbacks) {
+    delete callbacks;
+}
\ No newline at end of file