blob: 70d00d16f4e7e7d12ff738621719c03a98cba1bc [file] [log] [blame] [edit]
/**
* Copyright 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.
*/
#pragma once
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <input/Input.h>
#include <input/InputTransport.h>
#include <input/Resampler.h>
#include <utils/Looper.h>
namespace android {
/**
* An interface to receive batched input events. Even if you don't want batching, you still have to
* use this interface, and some of the events will be batched if your implementation is slow to
* handle the incoming input. The events received by these callbacks are never null.
*/
class InputConsumerCallbacks {
public:
virtual ~InputConsumerCallbacks(){};
virtual void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) = 0;
virtual void onMotionEvent(std::unique_ptr<MotionEvent> event, uint32_t seq) = 0;
/**
* When you receive this callback, you must (eventually) call "consumeBatchedInputEvents".
* If you don't want batching, then call "consumeBatchedInputEvents" immediately with
* std::nullopt requestedFrameTime to receive the pending motion event(s).
* @param pendingBatchSource the source of the pending batch.
*/
virtual void onBatchedInputEventPending(int32_t pendingBatchSource) = 0;
virtual void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) = 0;
virtual void onCaptureEvent(std::unique_ptr<CaptureEvent> event, uint32_t seq) = 0;
virtual void onDragEvent(std::unique_ptr<DragEvent> event, uint32_t seq) = 0;
virtual void onTouchModeEvent(std::unique_ptr<TouchModeEvent> event, uint32_t seq) = 0;
};
/**
* Consumes input events from an input channel.
*
* This is a re-implementation of InputConsumer. At the moment it only supports resampling for
* single pointer events. A lot of the higher-level logic has been folded into this class, to make
* it easier to use. In the legacy class, InputConsumer, the consumption logic was partially handled
* in the jni layer, as well as various actions like adding the fd to the Choreographer.
*
* TODO(b/297226446): use this instead of "InputConsumer":
* - Add resampling for multiple pointer events.
* - Allow various resampling strategies to be specified
* - Delete the old "InputConsumer" and use this class instead, renaming it to "InputConsumer".
* - Add tracing
* - Update all tests to use the new InputConsumer
*
* This class is not thread-safe. We are currently allowing the constructor to run on any thread,
* but all of the remaining APIs should be invoked on the looper thread only.
*/
class InputConsumerNoResampling final {
public:
/**
* @param callbacks are used to interact with InputConsumerNoResampling. They're called whenever
* the event is ready to consume.
* @param looper needs to be sp and not shared_ptr because it inherits from
* RefBase
* @param resamplerCreator callable that returns the resampling strategy to be used. If null, no
* resampling will be performed. resamplerCreator must never return nullptr.
*/
explicit InputConsumerNoResampling(
const std::shared_ptr<InputChannel>& channel, sp<Looper> looper,
InputConsumerCallbacks& callbacks,
std::function<std::unique_ptr<Resampler>()> resamplerCreator);
~InputConsumerNoResampling();
/**
* Must be called exactly once for each event received through the callbacks.
*/
void finishInputEvent(uint32_t seq, bool handled);
void reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime, nsecs_t presentTime);
/**
* If you want to consume all events immediately (disable batching), then you still must call
* this. For requestedFrameTime, use a std::nullopt. It is not guaranteed that the consumption
* will occur at requestedFrameTime. The resampling strategy may modify it.
* @param requestedFrameTime the time up to which consume the events. When there's double (or
* triple) buffering, you may want to not consume all events currently available, because you
* could be still working on an older frame, but there could already have been events that
* arrived that are more recent.
* @return whether any events were actually consumed
*/
bool consumeBatchedInputEvents(std::optional<nsecs_t> requestedFrameTime);
/**
* Returns true when there is *likely* a pending batch or a pending event in the channel.
*
* This is only a performance hint and may return false negative results. Clients should not
* rely on availability of the message based on the return value.
*/
bool probablyHasInput() const;
std::string getName() { return mChannel->getName(); }
std::string dump() const;
private:
std::shared_ptr<InputChannel> mChannel;
sp<Looper> mLooper;
InputConsumerCallbacks& mCallbacks;
const std::function<std::unique_ptr<Resampler>()> mResamplerCreator;
/**
* A map to manage multidevice resampling. Each contained resampler is never null. This map is
* only modified by handleMessages.
*/
std::map<DeviceId, std::unique_ptr<Resampler>> mResamplers;
// Looper-related infrastructure
/**
* This class is needed to associate the function "handleReceiveCallback" with the provided
* looper. The callback sent to the looper is RefBase - based, so we can't just send a reference
* of this class directly to the looper.
*/
class LooperEventCallback : public LooperCallback {
public:
LooperEventCallback(std::function<int(int events)> callback) : mCallback(callback) {}
int handleEvent(int /*fd*/, int events, void* /*data*/) override {
return mCallback(events);
}
private:
const std::function<int(int events)> mCallback;
};
sp<LooperEventCallback> mCallback;
/**
* The actual code that executes when the looper encounters available data on the InputChannel.
*/
int handleReceiveCallback(int events);
int mFdEvents;
void setFdEvents(int events);
void ensureCalledOnLooperThread(const char* func) const;
// Event-reading infrastructure
/**
* A fifo queue of events to be sent to the InputChannel. We can't send all InputMessages to
* the channel immediately when they are produced, because it's possible that the InputChannel
* is blocked (if the channel buffer is full). When that happens, we don't want to drop the
* events. Therefore, events should only be erased from the queue after they've been
* successfully written to the InputChannel.
*/
std::queue<InputMessage> mOutboundQueue;
/**
* Try to send all of the events in mOutboundQueue over the InputChannel. Not all events might
* actually get sent, because it's possible that the channel is blocked.
*/
void processOutboundEvents();
/**
* The time at which each event with the sequence number 'seq' was consumed.
* This data is provided in 'finishInputEvent' so that the receiving end can measure the latency
* This collection is populated when the event is received, and the entries are erased when the
* events are finished. It should not grow infinitely because if an event is not ack'd, ANR
* will be raised for that connection, and no further events will be posted to that channel.
*/
std::unordered_map<uint32_t /*seq*/, nsecs_t /*consumeTime*/> mConsumeTimes;
/**
* Find and return the consumeTime associated with the provided sequence number. Crashes if
* the provided seq number is not found.
*/
nsecs_t popConsumeTime(uint32_t seq);
// Event reading and processing
/**
* Read all of the available events from the InputChannel
*/
std::vector<InputMessage> readAllMessages();
/**
* Send InputMessage to the corresponding InputConsumerCallbacks function.
* @param msg
*/
void handleMessage(const InputMessage& msg) const;
// Batching
/**
* Batch messages that can be batched. When an unbatchable message is encountered, send it
* to the InputConsumerCallbacks immediately. If there are batches remaining,
* notify InputConsumerCallbacks. If a resampleable ACTION_DOWN message is received, then a
* resampler is inserted for that deviceId in mResamplers. If a resampleable ACTION_UP or
* ACTION_CANCEL message is received then the resampler associated to that deviceId is erased
* from mResamplers.
*/
void handleMessages(std::vector<InputMessage>&& messages);
/**
* Batched InputMessages, per deviceId.
* For each device, we are storing a queue of batched messages. These will all be collapsed into
* a single MotionEvent (up to a specific requestedFrameTime) when the consumer calls
* `consumeBatchedInputEvents`.
*/
std::map<DeviceId, std::queue<InputMessage>> mBatches;
/**
* Creates a MotionEvent by consuming samples from the provided queue. Consumes all messages
* with eventTime <= requestedFrameTime - resampleLatency, where `resampleLatency` is latency
* introduced by the resampler. Assumes that messages are queued in chronological order.
* @param requestedFrameTime The time up to which consume messages, as given by the inequality
* above. If std::nullopt, everything in messages will be consumed.
* @param messages the queue of messages to consume from.
*/
std::pair<std::unique_ptr<MotionEvent>, std::optional<uint32_t>> createBatchedMotionEvent(
const std::optional<nsecs_t> requestedFrameTime, std::queue<InputMessage>& messages);
/**
* Consumes the batched input events, optionally allowing the caller to specify a device id
* and/or requestedFrameTime threshold. It is not guaranteed that consumption will occur at
* requestedFrameTime.
* @param deviceId The device id from which to consume events. If std::nullopt, consumes events
* from any device id.
* @param requestedFrameTime The time up to which consume the events. If std::nullopt, consumes
* input events with any timestamp.
* @return Whether or not any events were consumed.
*/
bool consumeBatchedInputEvents(std::optional<DeviceId> deviceId,
std::optional<nsecs_t> requestedFrameTime);
/**
* A map from a single sequence number to several sequence numbers. This is needed because of
* batching. When batching is enabled, a single MotionEvent will contain several samples. Each
* sample came from an individual InputMessage of Type::Motion, and therefore will have to be
* finished individually. Therefore, when the app calls "finish" on a (possibly batched)
* MotionEvent, we will need to check this map in case there are multiple sequence numbers
* associated with a single number that the app provided.
*
* For example:
* Suppose we received 4 InputMessage's of type Motion, with action MOVE:
* InputMessage(MOVE) InputMessage(MOVE) InputMessage(MOVE) InputMessage(MOVE)
* seq=10 seq=11 seq=12 seq=13
* The app consumed them all as a batch, which means that the app received a single MotionEvent
* with historySize=3 and seq = 10.
*
* This map will look like:
* {
* 10: [11, 12, 13],
* }
* So the sequence number 10 will have 3 other sequence numbers associated with it.
* When the app calls 'finish' for seq=10, we need to call 'finish' 4 times total, for sequence
* numbers 10, 11, 12, 13. The app is not aware of the sequence numbers of each sample inside
* the batched MotionEvent that it received.
*/
std::map<uint32_t, std::vector<uint32_t>> mBatchedSequenceNumbers;
};
} // namespace android