blob: 7caa943c3e6079e47da125470d9bb01fcdee7cec [file] [log] [blame]
/*
* 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, nullptr),
mClientToken(clientToken),
mInputTransferToken(inputTransferToken) {}
// The InputConsumer does not keep the InputReceiver alive so the receiver is cleared once the
// owner releases it.
~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);
if (inputReceiver != nullptr) {
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;
}