diff options
66 files changed, 1363 insertions, 832 deletions
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index f1d8c72d85..fc0801cce8 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -228,10 +228,6 @@ on late-init chmod 0666 /sys/kernel/debug/tracing/events/thermal/cdev_update/enable chmod 0666 /sys/kernel/tracing/events/thermal/cdev_update/enable -# Tracing disabled by default - write /sys/kernel/debug/tracing/tracing_on 0 - write /sys/kernel/tracing/tracing_on 0 - # Read and truncate the kernel trace. chmod 0666 /sys/kernel/debug/tracing/trace chmod 0666 /sys/kernel/tracing/trace @@ -310,18 +306,9 @@ on late-init chmod 0666 /sys/kernel/tracing/events/synthetic/suspend_resume_minimal/enable chmod 0666 /sys/kernel/debug/tracing/events/synthetic/suspend_resume_minimal/enable -on late-init && property:ro.boot.fastboot.boottrace=enabled - setprop debug.atrace.tags.enableflags 802922 - setprop persist.traced.enable 0 - write /sys/kernel/tracing/events/binder/binder_transaction/enable 1 - write /sys/kernel/tracing/events/binder/binder_transaction_received/enable 1 - write /sys/kernel/tracing/events/binder/binder_transaction_alloc_buf/enable 1 - write /sys/kernel/tracing/events/binder/binder_set_priority/enable 1 - write /sys/kernel/tracing/events/binder/binder_lock/enable 1 - write /sys/kernel/tracing/events/binder/binder_locked/enable 1 - write /sys/kernel/tracing/events/binder/binder_unlock/enable 1 - write /sys/kernel/debug/tracing/tracing_on 1 - write /sys/kernel/tracing/tracing_on 1 +on late-init && property:ro.boot.fastboot.boottrace= + write /sys/kernel/debug/tracing/tracing_on 0 + write /sys/kernel/tracing/tracing_on 0 # Only create the tracing instance if persist.mm_events.enabled # Attempting to remove the tracing instance after it has been created @@ -534,7 +521,6 @@ on late-init && property:ro.boot.hypervisor.vm.supported=1 chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_mem_abort/id chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_mem_abort/id - on property:persist.debug.atrace.boottrace=1 start boottrace @@ -543,17 +529,3 @@ service boottrace /system/bin/atrace --async_start -f /data/misc/boottrace/categ user root disabled oneshot - -on property:sys.boot_completed=1 && property:ro.boot.fastboot.boottrace=enabled - setprop debug.atrace.tags.enableflags 0 - setprop persist.traced.enable 1 - write /sys/kernel/tracing/events/binder/binder_transaction/enable 0 - write /sys/kernel/tracing/events/binder/binder_transaction_received/enable 0 - write /sys/kernel/tracing/events/binder/binder_transaction_alloc_buf/enable 0 - write /sys/kernel/tracing/events/binder/binder_set_priority/enable 0 - write /sys/kernel/tracing/events/binder/binder_lock/enable 0 - write /sys/kernel/tracing/events/binder/binder_locked/enable 0 - write /sys/kernel/tracing/events/binder/binder_unlock/enable 0 - write /sys/kernel/debug/tracing/tracing_on 0 - write /sys/kernel/tracing/tracing_on 0 - diff --git a/cmds/installd/CrateManager.cpp b/cmds/installd/CrateManager.cpp index b17cba15d5..fd1df35aee 100644 --- a/cmds/installd/CrateManager.cpp +++ b/cmds/installd/CrateManager.cpp @@ -29,9 +29,10 @@ #include <sys/xattr.h> #include <unistd.h> +#include <utils.h> #include <fstream> +#include <functional> #include <string> -#include <utils.h> #include "utils.h" diff --git a/cmds/installd/CrateManager.h b/cmds/installd/CrateManager.h index 1f30b5dc79..d9b590f784 100644 --- a/cmds/installd/CrateManager.h +++ b/cmds/installd/CrateManager.h @@ -25,6 +25,7 @@ #include <sys/stat.h> #include <sys/types.h> +#include <functional> #include <optional> #include <string> #include <vector> diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index ecea1d2b1c..c43fdbd547 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -18,6 +18,7 @@ #ifndef UTILS_H_ #define UTILS_H_ +#include <functional> #include <string> #include <vector> diff --git a/data/etc/input/motion_predictor_config.xml b/data/etc/input/motion_predictor_config.xml index 03dfd63cbd..39772aece2 100644 --- a/data/etc/input/motion_predictor_config.xml +++ b/data/etc/input/motion_predictor_config.xml @@ -16,5 +16,20 @@ <motion-predictor> <!-- The time interval (ns) between the model's predictions. --> <prediction-interval>4166666</prediction-interval> <!-- 4.167 ms = ~240 Hz --> + <!-- The noise floor (px) for predicted distances. + + As the model is trained stochastically, there is some expected minimum + variability in its output. This can be a UX issue when the input device + is moving slowly and the variability is large relative to the magnitude + of the motion. In these cases, it is better to inhibit the prediction, + rather than show noisy predictions (and there is little benefit to + prediction anyway). + + The value for this parameter should at least be close to the maximum + predicted distance when the input device is held stationary (i.e. the + expected minimum variability), and perhaps a little larger to capture + the UX issue mentioned above. + --> + <distance-noise-floor>0.2</distance-noise-floor> </motion-predictor> diff --git a/data/etc/input/motion_predictor_model.tflite b/data/etc/input/motion_predictor_model.tflite Binary files differindex 10b3c8b114..45fc162cd1 100644 --- a/data/etc/input/motion_predictor_model.tflite +++ b/data/etc/input/motion_predictor_model.tflite diff --git a/include/input/Input.h b/include/input/Input.h index a271f0c1f9..64ee47342d 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -551,7 +551,7 @@ class KeyEvent : public InputEvent { public: virtual ~KeyEvent() { } - virtual InputEventType getType() const { return InputEventType::KEY; } + InputEventType getType() const override { return InputEventType::KEY; } inline int32_t getAction() const { return mAction; } @@ -602,7 +602,7 @@ class MotionEvent : public InputEvent { public: virtual ~MotionEvent() { } - virtual InputEventType getType() const { return InputEventType::MOTION; } + InputEventType getType() const override { return InputEventType::MOTION; } inline int32_t getAction() const { return mAction; } @@ -930,7 +930,7 @@ class FocusEvent : public InputEvent { public: virtual ~FocusEvent() {} - virtual InputEventType getType() const override { return InputEventType::FOCUS; } + InputEventType getType() const override { return InputEventType::FOCUS; } inline bool getHasFocus() const { return mHasFocus; } @@ -949,7 +949,7 @@ class CaptureEvent : public InputEvent { public: virtual ~CaptureEvent() {} - virtual InputEventType getType() const override { return InputEventType::CAPTURE; } + InputEventType getType() const override { return InputEventType::CAPTURE; } inline bool getPointerCaptureEnabled() const { return mPointerCaptureEnabled; } @@ -968,7 +968,7 @@ class DragEvent : public InputEvent { public: virtual ~DragEvent() {} - virtual InputEventType getType() const override { return InputEventType::DRAG; } + InputEventType getType() const override { return InputEventType::DRAG; } inline bool isExiting() const { return mIsExiting; } @@ -992,7 +992,7 @@ class TouchModeEvent : public InputEvent { public: virtual ~TouchModeEvent() {} - virtual InputEventType getType() const override { return InputEventType::TOUCH_MODE; } + InputEventType getType() const override { return InputEventType::TOUCH_MODE; } inline bool isInTouchMode() const { return mIsInTouchMode; } diff --git a/include/input/TfLiteMotionPredictor.h b/include/input/TfLiteMotionPredictor.h index fbd60261b2..2edc138f67 100644 --- a/include/input/TfLiteMotionPredictor.h +++ b/include/input/TfLiteMotionPredictor.h @@ -99,6 +99,14 @@ private: // A TFLite model for generating motion predictions. class TfLiteMotionPredictorModel { public: + struct Config { + // The time between predictions. + nsecs_t predictionInterval = 0; + // The noise floor for predictions. + // Distances (r) less than this should be discarded as noise. + float distanceNoiseFloor = 0; + }; + // Creates a model from an encoded Flatbuffer model. static std::unique_ptr<TfLiteMotionPredictorModel> create(); @@ -110,8 +118,7 @@ public: // Returns the length of the model's output buffers. size_t outputLength() const; - // Returns the time interval between predictions. - nsecs_t predictionInterval() const { return mPredictionInterval; } + const Config& config() const { return mConfig; } // Executes the model. // Returns true if the model successfully executed and the output tensors can be read. @@ -132,7 +139,7 @@ public: private: explicit TfLiteMotionPredictorModel(std::unique_ptr<android::base::MappedFile> model, - nsecs_t predictionInterval); + Config config); void allocateTensors(); void attachInputTensors(); @@ -154,7 +161,7 @@ private: std::unique_ptr<tflite::Interpreter> mInterpreter; tflite::SignatureRunner* mRunner = nullptr; - const nsecs_t mPredictionInterval = 0; + const Config mConfig = {}; }; } // namespace android diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs index 2d2bf7c582..1dc0b2471d 100644 --- a/libs/binder/rust/binder_tokio/lib.rs +++ b/libs/binder/rust/binder_tokio/lib.rs @@ -103,7 +103,12 @@ impl BinderAsyncPool for Tokio { // // This shouldn't cause issues with blocking the thread as only one task will run in a // call to `block_on`, so there aren't other tasks to block. - let result = spawn_me(); + // + // If the `block_in_place` call fails, then you are driving a current-thread runtime on + // the binder threadpool. Instead, it is recommended to use `TokioRuntime<Handle>` when + // the runtime is a current-thread runtime, as the current-thread runtime can be driven + // only by `Runtime::block_on` calls and not by `Handle::block_on`. + let result = tokio::task::block_in_place(spawn_me); Box::pin(after_spawn(result)) } else { let handle = tokio::task::spawn_blocking(spawn_me); diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 0bd0781cf4..463c210316 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -1023,17 +1023,7 @@ macro_rules! declare_binder_interface { } if ibinder.associate_class(<$native as $crate::binder_impl::Remotable>::get_class()) { - let service: std::result::Result<$crate::binder_impl::Binder<$native>, $crate::StatusCode> = - std::convert::TryFrom::try_from(ibinder.clone()); - if let Ok(service) = service { - // We were able to associate with our expected class and - // the service is local. - todo!() - //return Ok($crate::Strong::new(Box::new(service))); - } else { - // Service is remote - return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?))); - } + return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?))); } Err($crate::StatusCode::BAD_TYPE.into()) diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp index bc40864020..6712c9cece 100644 --- a/libs/binder/tests/binderAllocationLimits.cpp +++ b/libs/binder/tests/binderAllocationLimits.cpp @@ -216,16 +216,16 @@ TEST(RpcBinderAllocation, SetupRpcServer) { auto server = RpcServer::make(); server->setRootObject(sp<BBinder>::make()); - CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str())); + ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str())); std::thread([server]() { server->join(); }).detach(); - status_t status; auto session = RpcSession::make(); - status = session->setupUnixDomainClient(addr.c_str()); - CHECK_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str(); + status_t status = session->setupUnixDomainClient(addr.c_str()); + ASSERT_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str(); auto remoteBinder = session->getRootObject(); + ASSERT_NE(remoteBinder, nullptr); size_t mallocs = 0, totalBytes = 0; { @@ -233,7 +233,7 @@ TEST(RpcBinderAllocation, SetupRpcServer) { mallocs++; totalBytes += bytes; }); - CHECK_EQ(OK, remoteBinder->pingBinder()); + ASSERT_EQ(OK, remoteBinder->pingBinder()); } EXPECT_EQ(mallocs, 1); EXPECT_EQ(totalBytes, 40); diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index d352ce5bca..38c7f7cb6f 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -674,7 +674,7 @@ TEST_P(BinderRpc, SessionWithIncomingThreadpoolDoesntLeak) { // session 0 - will check for leaks in destrutor of proc // session 1 - we want to make sure it gets deleted when we drop all references to it auto proc = createRpcTestSocketServerProcess( - {.numThreads = 1, .numIncomingConnectionsBySession = {0, 1}, .numSessions = 2}); + {.numThreads = 1, .numSessions = 2, .numIncomingConnectionsBySession = {0, 1}}); wp<RpcSession> session = proc.proc->sessions.at(1).session; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 5bc05ef0d8..db99726739 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -377,7 +377,6 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId]; if (!callbackFunction) { - ALOGE("cannot call null callback function, skipping"); continue; } std::vector<SurfaceControlStats> surfaceControlStats; @@ -394,6 +393,11 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener callbackFunction(transactionStats.latchTime, transactionStats.presentFence, surfaceControlStats); + + // More than one transaction may contain the same callback id. Erase the callback from + // the map to ensure that it is only called once. This can happen if transactions are + // parcelled out of process and applied in both processes. + callbacksMap.erase(callbackId); } // handle on complete callbacks diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index bade68629d..50efac1314 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -556,7 +556,7 @@ const label* getValueLabelsForTypeAndCode(int32_t type, int32_t code) { if (type == EV_KEY) { return ev_key_value_labels; } - if (type == EV_MSC && code == ABS_MT_TOOL_TYPE) { + if (type == EV_ABS && code == ABS_MT_TOOL_TYPE) { return mt_tool_labels; } return nullptr; diff --git a/libs/input/MotionPredictor.cpp b/libs/input/MotionPredictor.cpp index 80a8d03ab9..0961a9d975 100644 --- a/libs/input/MotionPredictor.cpp +++ b/libs/input/MotionPredictor.cpp @@ -138,7 +138,8 @@ android::base::Result<void> MotionPredictor::record(const MotionEvent& event) { // Pass input event to the MetricsManager. if (!mMetricsManager) { mMetricsManager = - std::make_optional<MotionPredictorMetricsManager>(mModel->predictionInterval(), + std::make_optional<MotionPredictorMetricsManager>(mModel->config() + .predictionInterval, mModel->outputLength()); } mMetricsManager->onRecord(event); @@ -184,8 +185,18 @@ std::unique_ptr<MotionEvent> MotionPredictor::predict(nsecs_t timestamp) { const int64_t futureTime = timestamp + mPredictionTimestampOffsetNanos; for (int i = 0; i < predictedR.size() && predictionTime <= futureTime; ++i) { - // TODO(b/266747654): Stop predictions if confidence and/or predicted pressure are below - // some thresholds. + if (predictedR[i] < mModel->config().distanceNoiseFloor) { + // Stop predicting when the predicted output is below the model's noise floor. + // + // We assume that all subsequent predictions in the batch are unreliable because later + // predictions are conditional on earlier predictions, and a state of noise is not a + // good basis for prediction. + // + // The UX trade-off is that this potentially sacrifices some predictions when the input + // device starts to speed up, but avoids producing noisy predictions as it slows down. + break; + } + // TODO(b/266747654): Stop predictions if confidence is < some threshold. const TfLiteMotionPredictorSample::Point predictedPoint = convertPrediction(axisFrom, axisTo, predictedR[i], predictedPhi[i]); @@ -197,7 +208,7 @@ std::unique_ptr<MotionEvent> MotionPredictor::predict(nsecs_t timestamp) { coords.setAxisValue(AMOTION_EVENT_AXIS_Y, predictedPoint.y); coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, predictedPressure[i]); - predictionTime += mModel->predictionInterval(); + predictionTime += mModel->config().predictionInterval; if (i == 0) { hasPredictions = true; prediction->initialize(InputEvent::nextId(), event.getDeviceId(), event.getSource(), diff --git a/libs/input/TfLiteMotionPredictor.cpp b/libs/input/TfLiteMotionPredictor.cpp index 9f4aaa8337..5984b4d3b9 100644 --- a/libs/input/TfLiteMotionPredictor.cpp +++ b/libs/input/TfLiteMotionPredictor.cpp @@ -100,6 +100,16 @@ int64_t parseXMLInt64(const tinyxml2::XMLElement& configRoot, const char* elemen return value; } +float parseXMLFloat(const tinyxml2::XMLElement& configRoot, const char* elementName) { + const tinyxml2::XMLElement* element = configRoot.FirstChildElement(elementName); + LOG_ALWAYS_FATAL_IF(!element, "Could not find '%s' element", elementName); + + float value = 0; + LOG_ALWAYS_FATAL_IF(element->QueryFloatText(&value) != tinyxml2::XML_SUCCESS, + "Failed to parse %s: %s", elementName, element->GetText()); + return value; +} + // A TFLite ErrorReporter that logs to logcat. class LoggingErrorReporter : public tflite::ErrorReporter { public: @@ -152,6 +162,7 @@ std::unique_ptr<tflite::OpResolver> createOpResolver() { ::tflite::ops::builtin::Register_CONCATENATION()); resolver->AddBuiltin(::tflite::BuiltinOperator_FULLY_CONNECTED, ::tflite::ops::builtin::Register_FULLY_CONNECTED()); + resolver->AddBuiltin(::tflite::BuiltinOperator_GELU, ::tflite::ops::builtin::Register_GELU()); return resolver; } @@ -208,13 +219,7 @@ void TfLiteMotionPredictorBuffers::pushSample(int64_t timestamp, float phi = 0; float orientation = 0; - // Ignore the sample if there is no movement. These samples can occur when there's change to a - // property other than the coordinates and pollute the input to the model. - if (r == 0) { - return; - } - - if (!mAxisFrom) { // Second point. + if (!mAxisFrom && r > 0) { // Second point. // We can only determine the distance from the first point, and not any // angle. However, if the second point forms an axis, the orientation can // be transformed relative to that axis. @@ -235,8 +240,10 @@ void TfLiteMotionPredictorBuffers::pushSample(int64_t timestamp, } // Update the axis for the next point. - mAxisFrom = mAxisTo; - mAxisTo = sample; + if (r > 0) { + mAxisFrom = mAxisTo; + mAxisTo = sample; + } // Push the current sample onto the end of the input buffers. mInputR.pushBack(r); @@ -272,15 +279,18 @@ std::unique_ptr<TfLiteMotionPredictorModel> TfLiteMotionPredictorModel::create() // Parse configuration file. const tinyxml2::XMLElement* configRoot = configDocument.FirstChildElement("motion-predictor"); LOG_ALWAYS_FATAL_IF(!configRoot); - const nsecs_t predictionInterval = parseXMLInt64(*configRoot, "prediction-interval"); + Config config{ + .predictionInterval = parseXMLInt64(*configRoot, "prediction-interval"), + .distanceNoiseFloor = parseXMLFloat(*configRoot, "distance-noise-floor"), + }; return std::unique_ptr<TfLiteMotionPredictorModel>( - new TfLiteMotionPredictorModel(std::move(modelBuffer), predictionInterval)); + new TfLiteMotionPredictorModel(std::move(modelBuffer), std::move(config))); } TfLiteMotionPredictorModel::TfLiteMotionPredictorModel( - std::unique_ptr<android::base::MappedFile> model, nsecs_t predictionInterval) - : mFlatBuffer(std::move(model)), mPredictionInterval(predictionInterval) { + std::unique_ptr<android::base::MappedFile> model, Config config) + : mFlatBuffer(std::move(model)), mConfig(std::move(config)) { CHECK(mFlatBuffer); mErrorReporter = std::make_unique<LoggingErrorReporter>(); mModel = tflite::FlatBufferModel::VerifyAndBuildFromBuffer(mFlatBuffer->data(), diff --git a/libs/input/tests/MotionPredictor_test.cpp b/libs/input/tests/MotionPredictor_test.cpp index 7a62f5ec58..4ac7ae920e 100644 --- a/libs/input/tests/MotionPredictor_test.cpp +++ b/libs/input/tests/MotionPredictor_test.cpp @@ -72,11 +72,20 @@ TEST(MotionPredictorTest, IsPredictionAvailable) { ASSERT_FALSE(predictor.isPredictionAvailable(/*deviceId=*/1, AINPUT_SOURCE_TOUCHSCREEN)); } +TEST(MotionPredictorTest, StationaryNoiseFloor) { + MotionPredictor predictor(/*predictionTimestampOffsetNanos=*/1, + []() { return true /*enable prediction*/; }); + predictor.record(getMotionEvent(DOWN, 0, 1, 30ms)); + predictor.record(getMotionEvent(MOVE, 0, 1, 35ms)); // No movement. + std::unique_ptr<MotionEvent> predicted = predictor.predict(40 * NSEC_PER_MSEC); + ASSERT_EQ(nullptr, predicted); +} + TEST(MotionPredictorTest, Offset) { MotionPredictor predictor(/*predictionTimestampOffsetNanos=*/1, []() { return true /*enable prediction*/; }); predictor.record(getMotionEvent(DOWN, 0, 1, 30ms)); - predictor.record(getMotionEvent(MOVE, 0, 2, 35ms)); + predictor.record(getMotionEvent(MOVE, 0, 5, 35ms)); // Move enough to overcome the noise floor. std::unique_ptr<MotionEvent> predicted = predictor.predict(40 * NSEC_PER_MSEC); ASSERT_NE(nullptr, predicted); ASSERT_GE(predicted->getEventTime(), 41); diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h index ad4cc4a229..9fa5569e32 100644 --- a/libs/nativewindow/include/android/data_space.h +++ b/libs/nativewindow/include/android/data_space.h @@ -450,7 +450,7 @@ enum ADataSpace { * * Use limited range, SMPTE 2084 (PQ) transfer and BT2020 standard */ - ADATASPACE_BT2020_ITU_PQ = 298188800, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED + ADATASPACE_BT2020_ITU_PQ = 298188800, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED /** * Adobe RGB @@ -471,20 +471,20 @@ enum ADataSpace { ADATASPACE_JFIF = 146931712, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL /** - * ITU-R Recommendation 601 (BT.601) - 525-line + * ITU-R Recommendation 601 (BT.601) - 625-line * - * Standard-definition television, 525 Lines (NTSC) + * Standard-definition television, 625 Lines (PAL) * - * Use limited range, SMPTE 170M transfer and BT.601_525 standard. + * Use limited range, SMPTE 170M transfer and BT.601_625 standard. */ ADATASPACE_BT601_625 = 281149440, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED /** - * ITU-R Recommendation 709 (BT.709) + * ITU-R Recommendation 601 (BT.601) - 525-line * - * High-definition television + * Standard-definition television, 525 Lines (NTSC) * - * Use limited range, SMPTE 170M transfer and BT.709 standard. + * Use limited range, SMPTE 170M transfer and BT.601_525 standard. */ ADATASPACE_BT601_525 = 281280512, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h index cb61e6a320..494272b1a8 100644 --- a/libs/ui/include/ui/FatVector.h +++ b/libs/ui/include/ui/FatVector.h @@ -65,6 +65,17 @@ public: free(p); } } + + // The STL checks that this member type is present so that + // std::allocator_traits<InlineStdAllocator<T, SIZE>>::rebind_alloc<Other> + // works. std::vector won't be able to construct an + // InlineStdAllocator<Other, SIZE>, because InlineStdAllocator has no + // default constructor, but vector presumably doesn't rebind the allocator + // because it doesn't allocate internal node types. + template <class Other> + struct rebind { + typedef InlineStdAllocator<Other, SIZE> other; + }; Allocation& mAllocation; }; diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index f749b0e5b5..18f6dbc1e1 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -249,7 +249,7 @@ phony { "inputflinger_input_classifier_fuzzer", // Java/Kotlin targets - "CtsWindowManagerDeviceTestCases", + "CtsWindowManagerDeviceWindow", "InputTests", "CtsHardwareTestCases", "CtsInputTestCases", diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING index ca00e7dac2..c2da5bafaf 100644 --- a/services/inputflinger/TEST_MAPPING +++ b/services/inputflinger/TEST_MAPPING @@ -1,10 +1,10 @@ { "presubmit": [ { - "name": "CtsWindowManagerDeviceTestCases", + "name": "CtsWindowManagerDeviceWindow", "options": [ { - "include-filter": "android.server.wm.WindowInputTests" + "include-filter": "android.server.wm.window.WindowInputTests" } ] }, @@ -150,10 +150,10 @@ ], "hwasan-postsubmit": [ { - "name": "CtsWindowManagerDeviceTestCases", + "name": "CtsWindowManagerDeviceWindow", "options": [ { - "include-filter": "android.server.wm.WindowInputTests" + "include-filter": "android.server.wm.window.WindowInputTests" } ] }, diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index a93a2ea615..25e1d21850 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -437,7 +437,8 @@ public: /* Gets the keyboard layout for a particular input device. */ virtual std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( - const InputDeviceIdentifier& identifier) = 0; + const InputDeviceIdentifier& identifier, + const std::optional<KeyboardLayoutInfo> keyboardLayoutInfo) = 0; /* Gets a user-supplied alias for a particular input device, or an empty string if none. */ virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier) = 0; @@ -447,6 +448,9 @@ public: const std::string& inputDeviceDescriptor, ui::Rotation surfaceRotation) = 0; /* Notifies the input reader policy that a stylus gesture has started. */ virtual void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) = 0; + + /* Returns true if any InputConnection is currently active. */ + virtual bool isInputMethodConnectionActive() = 0; }; } // namespace android diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 2aaddf59bb..bacc7203b6 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -225,23 +225,6 @@ std::list<NotifyArgs> InputDevice::configure(nsecs_t when, mIsWaking = mConfiguration.getBool("device.wake").value_or(false); } - if (!changes.any() || changes.test(Change::KEYBOARD_LAYOUTS)) { - if (!mClasses.test(InputDeviceClass::VIRTUAL)) { - std::shared_ptr<KeyCharacterMap> keyboardLayout = - mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier); - bool shouldBumpGeneration = false; - for_each_subdevice( - [&keyboardLayout, &shouldBumpGeneration](InputDeviceContext& context) { - if (context.setKeyboardLayoutOverlay(keyboardLayout)) { - shouldBumpGeneration = true; - } - }); - if (shouldBumpGeneration) { - bumpGeneration(); - } - } - } - if (!changes.any() || changes.test(Change::DEVICE_ALIAS)) { if (!(mClasses.test(InputDeviceClass::VIRTUAL))) { std::string alias = mContext->getPolicy()->getDeviceAlias(mIdentifier); diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index ea95f7857a..08600b2db5 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -1040,6 +1040,16 @@ int32_t InputReader::ContextImpl::getLedMetaState() { return mReader->getLedMetaStateLocked(); } +void InputReader::ContextImpl::setPreventingTouchpadTaps(bool prevent) { + // lock is already held by the input loop + mReader->mPreventingTouchpadTaps = prevent; +} + +bool InputReader::ContextImpl::isPreventingTouchpadTaps() { + // lock is already held by the input loop + return mReader->mPreventingTouchpadTaps; +} + void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) { // lock is already held by the input loop mReader->disableVirtualKeysUntilLocked(time); diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 8347df8bdc..0bcab42417 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -626,16 +626,16 @@ private: ftl::Flags<InputDeviceClass> classes; - BitArray<KEY_MAX> keyBitmask; - BitArray<KEY_MAX> keyState; - BitArray<REL_MAX> relBitmask; - BitArray<SW_MAX> swBitmask; - BitArray<SW_MAX> swState; - BitArray<LED_MAX> ledBitmask; - BitArray<FF_MAX> ffBitmask; - BitArray<INPUT_PROP_MAX> propBitmask; - BitArray<MSC_MAX> mscBitmask; - BitArray<ABS_MAX> absBitmask; + BitArray<KEY_CNT> keyBitmask; + BitArray<KEY_CNT> keyState; + BitArray<REL_CNT> relBitmask; + BitArray<SW_CNT> swBitmask; + BitArray<SW_CNT> swState; + BitArray<LED_CNT> ledBitmask; + BitArray<FF_CNT> ffBitmask; + BitArray<INPUT_PROP_CNT> propBitmask; + BitArray<MSC_CNT> mscBitmask; + BitArray<ABS_CNT> absBitmask; struct AxisState { RawAbsoluteAxisInfo info; int value; diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index 9112913565..01ec7c1303 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -155,6 +155,9 @@ protected: int32_t getNextId() NO_THREAD_SAFETY_ANALYSIS override; void updateLedMetaState(int32_t metaState) REQUIRES(mReader->mLock) override; int32_t getLedMetaState() REQUIRES(mReader->mLock) REQUIRES(mLock) override; + void setPreventingTouchpadTaps(bool prevent) REQUIRES(mReader->mLock) + REQUIRES(mLock) override; + bool isPreventingTouchpadTaps() REQUIRES(mReader->mLock) REQUIRES(mLock) override; } mContext; friend class ContextImpl; @@ -185,6 +188,9 @@ private: std::unordered_map<std::shared_ptr<InputDevice>, std::vector<int32_t> /*eventHubId*/> mDeviceToEventHubIdsMap GUARDED_BY(mLock); + // true if tap-to-click on touchpad currently disabled + bool mPreventingTouchpadTaps GUARDED_BY(mLock){false}; + // low-level input event decoding and device management [[nodiscard]] std::list<NotifyArgs> processEventsLocked(const RawEvent* rawEvents, size_t count) REQUIRES(mLock); diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h index 0beace19ab..aed75636f7 100644 --- a/services/inputflinger/reader/include/InputReaderContext.h +++ b/services/inputflinger/reader/include/InputReaderContext.h @@ -62,6 +62,9 @@ public: virtual void updateLedMetaState(int32_t metaState) = 0; virtual int32_t getLedMetaState() = 0; + + virtual void setPreventingTouchpadTaps(bool prevent) = 0; + virtual bool isPreventingTouchpadTaps() = 0; }; } // namespace android diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp index e03a7730ae..58b29b82f9 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp @@ -86,20 +86,26 @@ int32_t KeyboardInputMapper::getDisplayId() { return ADISPLAY_ID_NONE; } +std::optional<KeyboardLayoutInfo> KeyboardInputMapper::getKeyboardLayoutInfo() const { + if (mKeyboardLayoutInfo) { + return mKeyboardLayoutInfo; + } + std::optional<RawLayoutInfo> layoutInfo = getDeviceContext().getRawLayoutInfo(); + if (!layoutInfo) { + return std::nullopt; + } + return KeyboardLayoutInfo(layoutInfo->languageTag, layoutInfo->layoutType); +} + void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo& info) { InputMapper::populateDeviceInfo(info); info.setKeyboardType(mKeyboardType); info.setKeyCharacterMap(getDeviceContext().getKeyCharacterMap()); - if (mKeyboardLayoutInfo) { - info.setKeyboardLayoutInfo(*mKeyboardLayoutInfo); - } else { - std::optional<RawLayoutInfo> layoutInfo = getDeviceContext().getRawLayoutInfo(); - if (layoutInfo) { - info.setKeyboardLayoutInfo( - KeyboardLayoutInfo(layoutInfo->languageTag, layoutInfo->layoutType)); - } + std::optional keyboardLayoutInfo = getKeyboardLayoutInfo(); + if (keyboardLayoutInfo) { + info.setKeyboardLayoutInfo(*keyboardLayoutInfo); } } @@ -152,13 +158,31 @@ std::list<NotifyArgs> KeyboardInputMapper::reconfigure(nsecs_t when, getValueByKey(config.keyboardLayoutAssociations, getDeviceContext().getLocation()); if (mKeyboardLayoutInfo != newKeyboardLayoutInfo) { mKeyboardLayoutInfo = newKeyboardLayoutInfo; + // Also update keyboard layout overlay as soon as we find the new layout info + updateKeyboardLayoutOverlay(); bumpGeneration(); } } + if (!changes.any() || changes.test(InputReaderConfiguration::Change::KEYBOARD_LAYOUTS)) { + if (!getDeviceContext().getDeviceClasses().test(InputDeviceClass::VIRTUAL) && + updateKeyboardLayoutOverlay()) { + bumpGeneration(); + } + } return out; } +bool KeyboardInputMapper::updateKeyboardLayoutOverlay() { + std::shared_ptr<KeyCharacterMap> keyboardLayout = + getDeviceContext() + .getContext() + ->getPolicy() + ->getKeyboardLayoutOverlay(getDeviceContext().getDeviceIdentifier(), + getKeyboardLayoutInfo()); + return getDeviceContext().setKeyboardLayoutOverlay(keyboardLayout); +} + void KeyboardInputMapper::configureParameters() { const PropertyMap& config = getDeviceContext().getConfiguration(); mParameters.orientationAware = config.getBool("keyboard.orientationAware").value_or(false); @@ -246,6 +270,7 @@ std::list<NotifyArgs> KeyboardInputMapper::processKey(nsecs_t when, nsecs_t read keyDown.flags = flags; mKeyDowns.push_back(keyDown); } + onKeyDownProcessed(); } else { // Remove key down. if (keyDownIndex) { @@ -423,4 +448,19 @@ std::list<NotifyArgs> KeyboardInputMapper::cancelAllDownKeys(nsecs_t when) { return out; } +void KeyboardInputMapper::onKeyDownProcessed() { + InputReaderContext& context = *getContext(); + if (context.isPreventingTouchpadTaps()) { + // avoid pinging java service unnecessarily + return; + } + // Ignore meta keys or multiple simultaneous down keys as they are likely to be keyboard + // shortcuts + bool shouldHideCursor = mKeyDowns.size() == 1 && !isMetaKey(mKeyDowns[0].keyCode); + if (shouldHideCursor && context.getPolicy()->isInputMethodConnectionActive()) { + context.fadePointer(); + context.setPreventingTouchpadTaps(true); + } +} + } // namespace android diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h index 45fd68b8bb..09808df18c 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h @@ -99,12 +99,15 @@ private: bool updateMetaStateIfNeeded(int32_t keyCode, bool down); std::optional<size_t> findKeyDownIndex(int32_t scanCode); + std::optional<KeyboardLayoutInfo> getKeyboardLayoutInfo() const; + bool updateKeyboardLayoutOverlay(); void resetLedState(); void initializeLedState(LedState& ledState, int32_t led); void updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset); std::optional<DisplayViewport> findViewport(const InputReaderConfiguration& readerConfig); [[nodiscard]] std::list<NotifyArgs> cancelAllDownKeys(nsecs_t when); + void onKeyDownProcessed(); }; } // namespace android diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp index e8263412e3..3abf2bd60b 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp @@ -153,6 +153,9 @@ NotifyMotionArgs GestureConverter::handleMove(nsecs_t when, nsecs_t readTime, const Gesture& gesture) { float deltaX = gesture.details.move.dx; float deltaY = gesture.details.move.dy; + if (std::abs(deltaX) > 0 || std::abs(deltaY) > 0) { + enableTapToClick(); + } rotateDelta(mOrientation, &deltaX, &deltaY); mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); @@ -191,6 +194,15 @@ std::list<NotifyArgs> GestureConverter::handleButtonsChange(nsecs_t when, nsecs_ coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0); coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0); + + if (mReaderContext.isPreventingTouchpadTaps()) { + enableTapToClick(); + if (gesture.details.buttons.is_tap) { + // return early to prevent this tap + return out; + } + } + const uint32_t buttonsPressed = gesture.details.buttons.down; bool pointerDown = isPointerDown(mButtonState) || buttonsPressed & @@ -337,6 +349,9 @@ std::list<NotifyArgs> GestureConverter::handleFling(nsecs_t when, nsecs_t readTi // magnitude, which will also result in the pointer icon being updated. // TODO(b/282023644): Add a signal in libgestures for when a stable contact has been // initiated with a touchpad. + if (!mReaderContext.isPreventingTouchpadTaps()) { + enableTapToClick(); + } return {handleMove(when, readTime, Gesture(kGestureMove, gesture.start_time, gesture.end_time, /*dx=*/0.f, @@ -545,7 +560,7 @@ NotifyMotionArgs GestureConverter::makeMotionArgs(nsecs_t when, nsecs_t readTime /* policyFlags= */ POLICY_FLAG_WAKE, action, /* actionButton= */ actionButton, - /* flags= */ 0, + /* flags= */ action == AMOTION_EVENT_ACTION_CANCEL ? AMOTION_EVENT_FLAG_CANCELED : 0, mReaderContext.getGlobalMetaState(), buttonState, mCurrentClassification, @@ -561,4 +576,8 @@ NotifyMotionArgs GestureConverter::makeMotionArgs(nsecs_t when, nsecs_t readTime /* videoFrames= */ {}}; } +void GestureConverter::enableTapToClick() { + mReaderContext.setPreventingTouchpadTaps(false); +} + } // namespace android diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h index b613b887cd..3ea3790620 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h @@ -78,6 +78,8 @@ private: const PointerCoords* pointerCoords, float xCursorPosition, float yCursorPosition); + void enableTapToClick(); + const int32_t mDeviceId; InputReaderContext& mReaderContext; std::shared_ptr<PointerControllerInterface> mPointerController; diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 38640b3f02..3d6df30b97 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -62,7 +62,9 @@ cc_test { "SlopController_test.cpp", "SyncQueue_test.cpp", "TestInputListener.cpp", + "TestInputListenerMatchers.cpp", "TouchpadInputMapper_test.cpp", + "KeyboardInputMapper_test.cpp", "UinputDevice.cpp", "UnwantedInteractionBlocker_test.cpp", ], diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp index 3486d0f2a4..78420c0d67 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp +++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp @@ -209,6 +209,14 @@ void FakeInputReaderPolicy::setStylusPointerIconEnabled(bool enabled) { mConfig.stylusPointerIconEnabled = enabled; } +void FakeInputReaderPolicy::setIsInputMethodConnectionActive(bool active) { + mIsInputMethodConnectionActive = active; +} + +bool FakeInputReaderPolicy::isInputMethodConnectionActive() { + return mIsInputMethodConnectionActive; +} + void FakeInputReaderPolicy::getReaderConfiguration(InputReaderConfiguration* outConfig) { *outConfig = mConfig; } @@ -227,7 +235,7 @@ void FakeInputReaderPolicy::notifyInputDevicesChanged( } std::shared_ptr<KeyCharacterMap> FakeInputReaderPolicy::getKeyboardLayoutOverlay( - const InputDeviceIdentifier&) { + const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) { return nullptr; } diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h index 85ff01a071..e03d28d0ac 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.h +++ b/services/inputflinger/tests/FakeInputReaderPolicy.h @@ -77,6 +77,8 @@ public: void setVelocityControlParams(const VelocityControlParameters& params); void setStylusButtonMotionEventsEnabled(bool enabled); void setStylusPointerIconEnabled(bool enabled); + void setIsInputMethodConnectionActive(bool active); + bool isInputMethodConnectionActive() override; private: void getReaderConfiguration(InputReaderConfiguration* outConfig) override; @@ -84,7 +86,7 @@ private: int32_t /*deviceId*/) override; void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override; std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( - const InputDeviceIdentifier&) override; + const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) override; std::string getDeviceAlias(const InputDeviceIdentifier&) override; void waitForInputDevices(std::function<void(bool)> processDevicesChanged); void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) override; @@ -99,6 +101,7 @@ private: std::vector<DisplayViewport> mViewports; TouchAffineTransformation transform; std::optional<int32_t /*deviceId*/> mStylusGestureNotified GUARDED_BY(mLock){}; + bool mIsInputMethodConnectionActive{false}; uint32_t mNextPointerCaptureSequenceNumber{0}; }; diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp index 482a266f77..4df0f69481 100644 --- a/services/inputflinger/tests/GestureConverter_test.cpp +++ b/services/inputflinger/tests/GestureConverter_test.cpp @@ -983,4 +983,226 @@ TEST_F(GestureConverterTest, FlingTapDown) { ASSERT_TRUE(mFakePointerController->isPointerShown()); } +TEST_F(GestureConverterTest, Tap) { + // Tap should produce button press/release events + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + + Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0, + /* vy= */ 0, GESTURES_FLING_TAP_DOWN); + std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + + ASSERT_EQ(1u, args.size()); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + + Gesture tapGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, + /* down= */ GESTURES_BUTTON_LEFT, + /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, tapGesture); + + ASSERT_EQ(5u, args.size()); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y), + WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f))); + args.pop_front(); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithPressure(1.0f))); + args.pop_front(); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(0), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(1.0f))); + args.pop_front(); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithCoords(POINTER_X, POINTER_Y), + WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), + WithButtonState(0), WithPressure(0.0f))); + args.pop_front(); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); +} + +TEST_F(GestureConverterTest, Click) { + // Click should produce button press/release events + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + + Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0, + /* vy= */ 0, GESTURES_FLING_TAP_DOWN); + std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + + ASSERT_EQ(1u, args.size()); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + + Gesture buttonDownGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, + /* down= */ GESTURES_BUTTON_LEFT, + /* up= */ GESTURES_BUTTON_NONE, /* is_tap= */ false); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, buttonDownGesture); + + ASSERT_EQ(2u, args.size()); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y), + WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f))); + args.pop_front(); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithPressure(1.0f))); + + Gesture buttonUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, + /* down= */ GESTURES_BUTTON_NONE, + /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ false); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, buttonUpGesture); + + ASSERT_EQ(3u, args.size()); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(0), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(1.0f))); + args.pop_front(); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithCoords(POINTER_X, POINTER_Y), + WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), + WithButtonState(0), WithPressure(0.0f))); + args.pop_front(); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); +} + +TEST_F(GestureConverterTest, TapWithTapToClickDisabled) { + // Tap should be ignored when disabled + mReader->getContext()->setPreventingTouchpadTaps(true); + + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + + Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0, + /* vy= */ 0, GESTURES_FLING_TAP_DOWN); + std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + + ASSERT_EQ(1u, args.size()); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + args.pop_front(); + + Gesture tapGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, + /* down= */ GESTURES_BUTTON_LEFT, + /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, tapGesture); + + // no events should be generated + ASSERT_EQ(0u, args.size()); + + // Future taps should be re-enabled + ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); +} + +TEST_F(GestureConverterTest, ClickWithTapToClickDisabled) { + // Click should still produce button press/release events + mReader->getContext()->setPreventingTouchpadTaps(true); + + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + + Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0, + /* vy= */ 0, GESTURES_FLING_TAP_DOWN); + std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + + ASSERT_EQ(1u, args.size()); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + + Gesture buttonDownGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, + /* down= */ GESTURES_BUTTON_LEFT, + /* up= */ GESTURES_BUTTON_NONE, /* is_tap= */ false); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, buttonDownGesture); + ASSERT_EQ(2u, args.size()); + + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y), + WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f))); + args.pop_front(); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithPressure(1.0f))); + + Gesture buttonUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, + /* down= */ GESTURES_BUTTON_NONE, + /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ false); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, buttonUpGesture); + + ASSERT_EQ(3u, args.size()); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(0), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(1.0f))); + args.pop_front(); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithCoords(POINTER_X, POINTER_Y), + WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), + WithButtonState(0), WithPressure(0.0f))); + args.pop_front(); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + + // Future taps should be re-enabled + ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); +} + +TEST_F(GestureConverterTest, MoveEnablesTapToClick) { + // initially disable tap-to-click + mReader->getContext()->setPreventingTouchpadTaps(true); + + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + + Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); + std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, moveGesture); + ASSERT_EQ(1u, args.size()); + + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X - 5, POINTER_Y + 10), WithRelativeMotion(-5, 10), + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + + ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 5, POINTER_Y + 10)); + + // Future taps should be re-enabled + ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); +} + } // namespace android diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index bc87c8e7df..6d9cd87c4f 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -16,6 +16,7 @@ #include "../dispatcher/InputDispatcher.h" #include "../BlockingQueue.h" +#include "TestInputListenerMatchers.h" #include <NotifyArgsBuilders.h> #include <android-base/properties.h> @@ -107,6 +108,23 @@ static constexpr gui::Pid MONITOR_PID{2001}; static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms; +/** + * If we expect to receive the event, the timeout can be made very long. When the test are running + * correctly, we will actually never wait until the end of the timeout because the wait will end + * when the event comes in. Still, this value shouldn't be infinite. During development, a local + * change may cause the test to fail. This timeout should be short enough to not annoy so that the + * developer can see the failure quickly (on human scale). + */ +static constexpr std::chrono::duration CONSUME_TIMEOUT_EVENT_EXPECTED = 1000ms; +/** + * When no event is expected, we can have a very short timeout. A large value here would slow down + * the tests. In the unlikely event of system being too slow, the event may still be present but the + * timeout would complete before it is consumed. This would result in test flakiness. If this + * occurs, the flakiness rate would be high. Since the flakes are treated with high priority, this + * would get noticed and addressed quickly. + */ +static constexpr std::chrono::duration CONSUME_TIMEOUT_NO_EVENT_EXPECTED = 10ms; + static constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; @@ -136,41 +154,10 @@ static void assertMotionAction(int32_t expectedAction, int32_t receivedAction) { << MotionEvent::actionToString(receivedAction); } -MATCHER_P(WithMotionAction, action, "MotionEvent with specified action") { - bool matches = action == arg.getAction(); - if (!matches) { - *result_listener << "expected action " << MotionEvent::actionToString(action) - << ", but got " << MotionEvent::actionToString(arg.getAction()); - } - if (action == AMOTION_EVENT_ACTION_DOWN) { - if (!matches) { - *result_listener << "; "; - } - *result_listener << "downTime should match eventTime for ACTION_DOWN events"; - matches &= arg.getDownTime() == arg.getEventTime(); - } - if (action == AMOTION_EVENT_ACTION_CANCEL) { - if (!matches) { - *result_listener << "; "; - } - *result_listener << "expected FLAG_CANCELED to be set with ACTION_CANCEL, but was not set"; - matches &= (arg.getFlags() & AMOTION_EVENT_FLAG_CANCELED) != 0; - } - return matches; -} - MATCHER_P(WithDownTime, downTime, "InputEvent with specified downTime") { return arg.getDownTime() == downTime; } -MATCHER_P(WithDisplayId, displayId, "InputEvent with specified displayId") { - return arg.getDisplayId() == displayId; -} - -MATCHER_P(WithDeviceId, deviceId, "InputEvent with specified deviceId") { - return arg.getDeviceId() == deviceId; -} - MATCHER_P(WithSource, source, "InputEvent with specified source") { *result_listener << "expected source " << inputEventSourceToString(source) << ", but got " << inputEventSourceToString(arg.getSource()); @@ -892,9 +879,9 @@ public: mConsumer = std::make_unique<InputConsumer>(std::move(clientChannel)); } - InputEvent* consume() { + InputEvent* consume(std::chrono::milliseconds timeout) { InputEvent* event; - std::optional<uint32_t> consumeSeq = receiveEvent(&event); + std::optional<uint32_t> consumeSeq = receiveEvent(timeout, &event); if (!consumeSeq) { return nullptr; } @@ -906,7 +893,8 @@ public: * Receive an event without acknowledging it. * Return the sequence number that could later be used to send finished signal. */ - std::optional<uint32_t> receiveEvent(InputEvent** outEvent = nullptr) { + std::optional<uint32_t> receiveEvent(std::chrono::milliseconds timeout, + InputEvent** outEvent = nullptr) { uint32_t consumeSeq; InputEvent* event; @@ -916,7 +904,7 @@ public: status = mConsumer->consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq, &event); std::chrono::duration elapsed = std::chrono::steady_clock::now() - start; - if (elapsed > 100ms) { + if (elapsed > timeout) { break; } } @@ -956,7 +944,7 @@ public: void consumeEvent(InputEventType expectedEventType, int32_t expectedAction, std::optional<int32_t> expectedDisplayId, std::optional<int32_t> expectedFlags) { - InputEvent* event = consume(); + InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event."; @@ -1002,7 +990,7 @@ public: } MotionEvent* consumeMotion() { - InputEvent* event = consume(); + InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); if (event == nullptr) { ADD_FAILURE() << mName << ": expected a MotionEvent, but didn't get one."; @@ -1023,7 +1011,7 @@ public: } void consumeFocusEvent(bool hasFocus, bool inTouchMode) { - InputEvent* event = consume(); + InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event."; ASSERT_EQ(InputEventType::FOCUS, event->getType()) @@ -1037,7 +1025,7 @@ public: } void consumeCaptureEvent(bool hasCapture) { - const InputEvent* event = consume(); + const InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event."; ASSERT_EQ(InputEventType::CAPTURE, event->getType()) @@ -1051,7 +1039,7 @@ public: } void consumeDragEvent(bool isExiting, float x, float y) { - const InputEvent* event = consume(); + const InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event."; ASSERT_EQ(InputEventType::DRAG, event->getType()) << "Instead of DragEvent, got " << *event; @@ -1066,7 +1054,7 @@ public: } void consumeTouchModeEvent(bool inTouchMode) { - const InputEvent* event = consume(); + const InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event."; ASSERT_EQ(InputEventType::TOUCH_MODE, event->getType()) @@ -1079,7 +1067,7 @@ public: } void assertNoEvents() { - InputEvent* event = consume(); + InputEvent* event = consume(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); if (event == nullptr) { return; } @@ -1262,6 +1250,25 @@ public: void setWindowOffset(float offsetX, float offsetY) { mInfo.transform.set(offsetX, offsetY); } + KeyEvent* consumeKey() { + InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); + if (event == nullptr) { + ADD_FAILURE() << "Consume failed : no event"; + return nullptr; + } + if (event->getType() != InputEventType::KEY) { + ADD_FAILURE() << "Instead of key event, got " << *event; + return nullptr; + } + return static_cast<KeyEvent*>(event); + } + + void consumeKeyEvent(const ::testing::Matcher<KeyEvent>& matcher) { + KeyEvent* keyEvent = consumeKey(); + ASSERT_NE(nullptr, keyEvent) << "Did not get a key event, but expected " << matcher; + ASSERT_THAT(*keyEvent, matcher); + } + void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) { consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId, expectedFlags); } @@ -1322,13 +1329,11 @@ public: void consumeMotionOutsideWithZeroedCoords(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { - InputEvent* event = consume(); - ASSERT_NE(nullptr, event); - ASSERT_EQ(InputEventType::MOTION, event->getType()); - const MotionEvent& motionEvent = static_cast<MotionEvent&>(*event); - EXPECT_EQ(AMOTION_EVENT_ACTION_OUTSIDE, motionEvent.getActionMasked()); - EXPECT_EQ(0.f, motionEvent.getRawPointerCoords(0)->getX()); - EXPECT_EQ(0.f, motionEvent.getRawPointerCoords(0)->getY()); + MotionEvent* motionEvent = consumeMotion(); + ASSERT_NE(nullptr, motionEvent); + EXPECT_EQ(AMOTION_EVENT_ACTION_OUTSIDE, motionEvent->getActionMasked()); + EXPECT_EQ(0.f, motionEvent->getRawPointerCoords(0)->getX()); + EXPECT_EQ(0.f, motionEvent->getRawPointerCoords(0)->getY()); } void consumeFocusEvent(bool hasFocus, bool inTouchMode = true) { @@ -1372,7 +1377,7 @@ public: ADD_FAILURE() << "Invalid receive event on window with no receiver"; return std::nullopt; } - return mInputReceiver->receiveEvent(outEvent); + return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED, outEvent); } void finishEvent(uint32_t sequenceNum) { @@ -1385,15 +1390,15 @@ public: mInputReceiver->sendTimeline(inputEventId, timeline); } - InputEvent* consume() { + InputEvent* consume(std::chrono::milliseconds timeout) { if (mInputReceiver == nullptr) { return nullptr; } - return mInputReceiver->consume(); + return mInputReceiver->consume(timeout); } MotionEvent* consumeMotion() { - InputEvent* event = consume(); + InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); if (event == nullptr) { ADD_FAILURE() << "Consume failed : no event"; return nullptr; @@ -1441,7 +1446,7 @@ private: std::atomic<int32_t> FakeWindowHandle::sId{1}; static InputEventInjectionResult injectKey( - const std::unique_ptr<InputDispatcher>& dispatcher, int32_t action, int32_t repeatCount, + InputDispatcher& dispatcher, int32_t action, int32_t repeatCount, int32_t displayId = ADISPLAY_ID_NONE, InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT, std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT, @@ -1459,10 +1464,19 @@ static InputEventInjectionResult injectKey( policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT; } // Inject event until dispatch out. - return dispatcher->injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags); + return dispatcher.injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags); +} + +static void assertInjectedKeyTimesOut(InputDispatcher& dispatcher) { + InputEventInjectionResult result = + injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_NONE, + InputEventInjectionSync::WAIT_FOR_RESULT, CONSUME_TIMEOUT_NO_EVENT_EXPECTED); + if (result != InputEventInjectionResult::TIMED_OUT) { + FAIL() << "Injection should have timed out, but got " << ftl::enum_string(result); + } } -static InputEventInjectionResult injectKeyDown(const std::unique_ptr<InputDispatcher>& dispatcher, +static InputEventInjectionResult injectKeyDown(InputDispatcher& dispatcher, int32_t displayId = ADISPLAY_ID_NONE) { return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId); } @@ -1470,30 +1484,30 @@ static InputEventInjectionResult injectKeyDown(const std::unique_ptr<InputDispat // Inject a down event that has key repeat disabled. This allows InputDispatcher to idle without // sending a subsequent key up. When key repeat is enabled, the dispatcher cannot idle because it // has to be woken up to process the repeating key. -static InputEventInjectionResult injectKeyDownNoRepeat( - const std::unique_ptr<InputDispatcher>& dispatcher, int32_t displayId = ADISPLAY_ID_NONE) { +static InputEventInjectionResult injectKeyDownNoRepeat(InputDispatcher& dispatcher, + int32_t displayId = ADISPLAY_ID_NONE) { return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId, InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false); } -static InputEventInjectionResult injectKeyUp(const std::unique_ptr<InputDispatcher>& dispatcher, +static InputEventInjectionResult injectKeyUp(InputDispatcher& dispatcher, int32_t displayId = ADISPLAY_ID_NONE) { return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, displayId); } static InputEventInjectionResult injectMotionEvent( - const std::unique_ptr<InputDispatcher>& dispatcher, const MotionEvent& event, + InputDispatcher& dispatcher, const MotionEvent& event, std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT, InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT, std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) { - return dispatcher->injectInputEvent(&event, targetUid, injectionMode, injectionTimeout, - policyFlags); + return dispatcher.injectInputEvent(&event, targetUid, injectionMode, injectionTimeout, + policyFlags); } static InputEventInjectionResult injectMotionEvent( - const std::unique_ptr<InputDispatcher>& dispatcher, int32_t action, int32_t source, - int32_t displayId, const PointF& position = {100, 200}, + InputDispatcher& dispatcher, int32_t action, int32_t source, int32_t displayId, + const PointF& position = {100, 200}, const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION}, std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT, @@ -1517,14 +1531,14 @@ static InputEventInjectionResult injectMotionEvent( targetUid, policyFlags); } -static InputEventInjectionResult injectMotionDown( - const std::unique_ptr<InputDispatcher>& dispatcher, int32_t source, int32_t displayId, - const PointF& location = {100, 200}) { +static InputEventInjectionResult injectMotionDown(InputDispatcher& dispatcher, int32_t source, + int32_t displayId, + const PointF& location = {100, 200}) { return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location); } -static InputEventInjectionResult injectMotionUp(const std::unique_ptr<InputDispatcher>& dispatcher, - int32_t source, int32_t displayId, +static InputEventInjectionResult injectMotionUp(InputDispatcher& dispatcher, int32_t source, + int32_t displayId, const PointF& location = {100, 200}) { return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location); } @@ -1634,7 +1648,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; // Window should receive motion event. @@ -1649,7 +1663,7 @@ TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // Inject a MotionEvent to an unknown display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_NONE)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_NONE)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; // Window should receive motion event. @@ -1669,7 +1683,7 @@ TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1689,7 +1703,7 @@ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1708,7 +1722,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) { mDispatcher->onWindowInfosChanged( {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; // Top window should receive the touch down event. Second window should not receive anything. @@ -1735,7 +1749,7 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance mDispatcher->onWindowInfosChanged( {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1744,7 +1758,7 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {110, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1814,7 +1828,7 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { mDispatcher->onWindowInfosChanged( {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1823,7 +1837,7 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {110, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1865,7 +1879,7 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { // Touch down on top window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1881,7 +1895,7 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1897,14 +1911,14 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; foregroundWindow->consumeMotionPointerUp(0); wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) @@ -1952,7 +1966,7 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { // Touch down on left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1968,7 +1982,7 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(300).y(100)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1994,7 +2008,7 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(310).y(110)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)); rightWindow->consumeMotionMove(); @@ -2032,7 +2046,7 @@ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) { // Touch down on left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -2042,7 +2056,7 @@ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) { // Move to right window, the left window should receive cancel. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {201, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -2161,86 +2175,74 @@ TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) { const int32_t touchDeviceId = 4; // Move the cursor from right ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) .downTime(baseTime + 10) .eventTime(baseTime + 20) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(300) - .y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100)) .build())); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // .. to the left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) .downTime(baseTime + 10) .eventTime(baseTime + 30) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(110) - .y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100)) .build())); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // Now tap the left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .downTime(baseTime + 40) .eventTime(baseTime + 40) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); // release tap ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .downTime(baseTime + 40) .eventTime(baseTime + 50) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); // Tap the window on the right ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .downTime(baseTime + 60) .eventTime(baseTime + 60) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(300) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .build())); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); // release tap ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .downTime(baseTime + 60) .eventTime(baseTime + 70) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(300) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .build())); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); @@ -2526,12 +2528,10 @@ TEST_F(InputDispatcherTest, UnfinishedInjectedEvent) { // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after // completion. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(50) - .y(50)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50)) .build())); window->consumeMotionEvent( AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID))); @@ -2579,35 +2579,29 @@ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { const int32_t touchDeviceId = 4; // Hover over the left window. Keep the cursor there. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(50) - .y(50)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // Tap on left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); @@ -2615,27 +2609,21 @@ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { // First finger down on right window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(300) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .build())); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); // Second finger down on the left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(300) - .y(100)) - .pointer(PointerBuilder(1, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); @@ -2662,32 +2650,28 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { const int32_t touchDeviceId = 4; // Start hovering with stylus ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) - .pointer(PointerBuilder(0, ToolType::STYLUS) - .x(50) - .y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // Finger down on the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); // Try to continue hovering with stylus. Since we are already down, injection should fail ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) @@ -2698,19 +2682,17 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { // Lift up the finger ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); // Now that the touch is gone, stylus hovering should start working again ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) @@ -2953,22 +2935,21 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) { mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}})); mDispatcher->waitForIdle(); - InputEvent* inputEvent1 = window1->consume(); - ASSERT_NE(inputEvent1, nullptr); + + MotionEvent* motionEvent1 = window1->consumeMotion(); + ASSERT_NE(motionEvent1, nullptr); window2->assertNoEvents(); - MotionEvent& motionEvent1 = static_cast<MotionEvent&>(*inputEvent1); - nsecs_t downTimeForWindow1 = motionEvent1.getDownTime(); - ASSERT_EQ(motionEvent1.getDownTime(), motionEvent1.getEventTime()); + nsecs_t downTimeForWindow1 = motionEvent1->getDownTime(); + ASSERT_EQ(motionEvent1->getDownTime(), motionEvent1->getEventTime()); // Now touch down on the window with another pointer mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}})); mDispatcher->waitForIdle(); - InputEvent* inputEvent2 = window2->consume(); - ASSERT_NE(inputEvent2, nullptr); - MotionEvent& motionEvent2 = static_cast<MotionEvent&>(*inputEvent2); - nsecs_t downTimeForWindow2 = motionEvent2.getDownTime(); + MotionEvent* motionEvent2 = window2->consumeMotion(); + ASSERT_NE(motionEvent2, nullptr); + nsecs_t downTimeForWindow2 = motionEvent2->getDownTime(); ASSERT_NE(downTimeForWindow1, downTimeForWindow2); - ASSERT_EQ(motionEvent2.getDownTime(), motionEvent2.getEventTime()); + ASSERT_EQ(motionEvent2->getDownTime(), motionEvent2->getEventTime()); // Now move the pointer on the second window mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}})); @@ -3012,7 +2993,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { // Start cursor position in right window so that we can move the cursor to left window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400)) @@ -3021,7 +3002,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { // Move cursor into left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3031,7 +3012,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { // Inject a series of mouse events for a mouse click ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3040,7 +3021,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) @@ -3050,7 +3031,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE, AINPUT_SOURCE_MOUSE) .buttonState(0) @@ -3060,7 +3041,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) .buttonState(0) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3069,7 +3050,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { // Move mouse cursor back to right window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400)) @@ -3157,12 +3138,10 @@ TEST_F(InputDispatcherTest, HoverWithSpyWindows) { // Send mouse cursor to the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) .build())); window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), @@ -3191,22 +3170,18 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { // Send mouse cursor to the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) .build())); // Move mouse cursor ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(110) - .y(110)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110)) .build())); window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), @@ -3219,13 +3194,11 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { WithSource(AINPUT_SOURCE_MOUSE))); // Touch down on the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(SECOND_DEVICE_ID) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(200) - .y(200)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200)) .build())); window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT), WithSource(AINPUT_SOURCE_MOUSE))); @@ -3243,13 +3216,11 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { // Touch UP on the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(SECOND_DEVICE_ID) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(200) - .y(200)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200)) .build())); spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); @@ -3260,13 +3231,11 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { // One more tap - DOWN ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(SECOND_DEVICE_ID) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(250) - .y(250)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250)) .build())); window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); @@ -3275,13 +3244,11 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { // Touch UP on the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(SECOND_DEVICE_ID) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(250) - .y(250)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250)) .build())); window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); @@ -3305,7 +3272,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3313,7 +3280,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // Inject a series of mouse events for a mouse click ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3322,7 +3289,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) @@ -3332,7 +3299,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE, AINPUT_SOURCE_MOUSE) .buttonState(0) @@ -3342,7 +3309,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) .buttonState(0) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3352,7 +3319,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { // We already canceled the hovering implicitly by injecting the "DOWN" event without lifting the // hover first. Therefore, injection of HOVER_EXIT is inconsistent, and should fail. ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3375,12 +3342,10 @@ TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(300) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); @@ -3482,13 +3447,11 @@ TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) { // Set cursor position in window in default display and check that hover enter and move // events are generated. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .displayId(ADISPLAY_ID_DEFAULT) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(300) - .y(600)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(600)) .build())); windowDefaultDisplay->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); @@ -3503,13 +3466,11 @@ TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) { mDispatcher->onWindowInfosChanged( {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .displayId(ADISPLAY_ID_DEFAULT) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(400) - .y(700)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(400).y(700)) .build())); windowDefaultDisplay->consumeMotionEvent( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), @@ -3535,7 +3496,7 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { // Inject an event with coordinate in the area of right window, with mouse cursor in the area of // left window. This event should be dispatched to the left window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, {610, 400}, {599, 400})); windowLeft->consumeMotionDown(ADISPLAY_ID_DEFAULT); windowRight->assertNoEvents(); @@ -3777,7 +3738,7 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -3790,7 +3751,7 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -4106,7 +4067,7 @@ TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) { // Send down to the first window. The point is represented in the logical display space. The // point is selected so that if the hit test was done in logical display space, then it would // end up in the incorrect window. - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, PointF{75 * 2, 55 * 4}); firstWindow->consumeMotionDown(); @@ -4133,7 +4094,7 @@ TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisp .build(); event.transform(matrix); - injectMotionEvent(mDispatcher, event, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, event, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT); firstWindow->consumeMotionDown(); @@ -4630,7 +4591,7 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -4645,14 +4606,14 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { secondWindowInPrimary->consumeMotionDown(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; firstWindowInPrimary->assertNoEvents(); secondWindowInPrimary->consumeMotionMove(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; firstWindowInPrimary->assertNoEvents(); @@ -4690,7 +4651,8 @@ TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { // Touch on second display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {50, 50})) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, + {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; // Window should receive motion event. @@ -4704,14 +4666,14 @@ TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { secondWindowInPrimary->consumeMotionDown(SECOND_DISPLAY_ID); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; firstWindowInPrimary->assertNoEvents(); secondWindowInPrimary->consumeMotionMove(SECOND_DISPLAY_ID); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50})) + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; firstWindowInPrimary->assertNoEvents(); secondWindowInPrimary->consumeMotionUp(SECOND_DISPLAY_ID); @@ -4832,7 +4794,7 @@ TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -4961,7 +4923,9 @@ public: expectedFlags); } - std::optional<int32_t> receiveEvent() { return mInputReceiver->receiveEvent(); } + std::optional<int32_t> receiveEvent() { + return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED); + } void finishEvent(uint32_t consumeSeq) { return mInputReceiver->finishEvent(consumeSeq); } @@ -4994,18 +4958,7 @@ public: /*expectedFlags=*/0); } - MotionEvent* consumeMotion() { - InputEvent* event = mInputReceiver->consume(); - if (!event) { - ADD_FAILURE() << "No event was produced"; - return nullptr; - } - if (event->getType() != InputEventType::MOTION) { - ADD_FAILURE() << "Expected MotionEvent, got " << *event; - return nullptr; - } - return static_cast<MotionEvent*>(event); - } + MotionEvent* consumeMotion() { return mInputReceiver->consumeMotion(); } void assertNoEvents() { mInputReceiver->assertNoEvents(); } @@ -5032,7 +4985,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDis mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -5041,7 +4994,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDis monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {110, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -5056,7 +5009,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDis // If more events come in, there will be no more foreground window to send them to. This will // cause a cancel for the monitor, as well. ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {120, 200})) << "Injection should fail because the window was removed"; window->assertNoEvents(); @@ -5073,7 +5026,7 @@ TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) { FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -5088,7 +5041,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); window->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -5098,7 +5051,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) { EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken())); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -5117,7 +5070,7 @@ TEST_F(InputDispatcherMonitorTest, NoWindowTransform) { FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); MotionEvent* event = monitor.consumeMotion(); @@ -5130,7 +5083,7 @@ TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) { FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Injection should fail if there is a monitor, but no touchable window"; monitor.assertNoEvents(); } @@ -5228,7 +5181,7 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN); mDispatcher->notifyKey(keyArgs); - InputEvent* event = window->consume(); + KeyEvent* event = window->consumeKey(); ASSERT_NE(event, nullptr); std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event); @@ -5272,7 +5225,7 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(motionArgs); - InputEvent* event = window->consume(); + MotionEvent* event = window->consumeMotion(); ASSERT_NE(event, nullptr); std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event); @@ -5371,7 +5324,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow) { setFocusedWindow(windowSecond); windowSecond->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; // Focused window should receive event. @@ -5392,8 +5345,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) { setFocusedWindow(window); // Test inject a key down, should timeout. - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) - << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; + ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher)); // window channel is invalid, so it should not receive any input event. window->assertNoEvents(); @@ -5410,8 +5362,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) { setFocusedWindow(window); // Test inject a key down, should timeout. - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) - << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; + ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher)); // window is not focusable, so it should not receive any input event. window->assertNoEvents(); @@ -5438,7 +5389,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) { windowSecond->consumeFocusEvent(true); windowTop->consumeFocusEvent(false); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; // Focused window should receive event. @@ -5461,7 +5412,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) { setFocusedWindow(windowTop); windowTop->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; // Event should be dropped. @@ -5492,8 +5443,8 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) { // Injected key goes to pending queue. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE)); + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, + ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE)); // Window does not get focus event or key down. window->assertNoEvents(); @@ -5774,15 +5725,8 @@ protected: void expectKeyRepeatOnce(int32_t repeatCount) { SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount)); - InputEvent* repeatEvent = mWindow->consume(); - ASSERT_NE(nullptr, repeatEvent); - - ASSERT_EQ(InputEventType::KEY, repeatEvent->getType()); - - KeyEvent* repeatKeyEvent = static_cast<KeyEvent*>(repeatEvent); - uint32_t eventAction = repeatKeyEvent->getAction(); - EXPECT_EQ(AKEY_EVENT_ACTION_DOWN, eventAction); - EXPECT_EQ(repeatCount, repeatKeyEvent->getRepeatCount()); + mWindow->consumeKeyEvent( + AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithRepeatCount(repeatCount))); } void sendAndConsumeKeyUp(int32_t deviceId) { @@ -5862,7 +5806,7 @@ TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFrom GTEST_SKIP() << "Flaky test (b/270393106)"; sendAndConsumeKeyDown(/*deviceId=*/1); for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { - InputEvent* repeatEvent = mWindow->consume(); + KeyEvent* repeatEvent = mWindow->consumeKey(); ASSERT_NE(nullptr, repeatEvent) << "Didn't receive event with repeat count " << repeatCount; EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER, IdGenerator::getSource(repeatEvent->getId())); @@ -5875,7 +5819,7 @@ TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEvent std::unordered_set<int32_t> idSet; for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { - InputEvent* repeatEvent = mWindow->consume(); + KeyEvent* repeatEvent = mWindow->consumeKey(); ASSERT_NE(nullptr, repeatEvent) << "Didn't receive event with repeat count " << repeatCount; int32_t id = repeatEvent->getId(); EXPECT_EQ(idSet.end(), idSet.find(id)); @@ -5935,14 +5879,14 @@ protected: TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) { // Test touch down on primary display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT); windowInSecondary->assertNoEvents(); // Test touch down on second display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->assertNoEvents(); windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID); @@ -5951,13 +5895,13 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) { // Test inject a key down with display id specified. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectKeyDownNoRepeat(mDispatcher, ADISPLAY_ID_DEFAULT)) + injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT); windowInSecondary->assertNoEvents(); // Test inject a key down without display id specified. - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->assertNoEvents(); windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE); @@ -5970,8 +5914,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) AKEY_EVENT_FLAG_CANCELED); // Test inject a key down, should timeout because of no target window. - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDownNoRepeat(mDispatcher)) - << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; + ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher)); windowInPrimary->assertNoEvents(); windowInSecondary->consumeFocusEvent(false); windowInSecondary->assertNoEvents(); @@ -5986,7 +5929,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { // Test touch down on primary display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT); monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -5995,7 +5938,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { // Test touch down on second display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->assertNoEvents(); monitorInPrimary.assertNoEvents(); @@ -6004,7 +5947,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { // Lift up the touch from the second display ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID); monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID); @@ -6013,7 +5956,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { // If specific a display, it will dispatch to the focused window of particular display, // or it will dispatch to the focused window of focused display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->assertNoEvents(); monitorInPrimary.assertNoEvents(); @@ -6030,7 +5973,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) { FakeMonitorReceiver(mDispatcher, "M_2", SECOND_DISPLAY_ID); // Test inject a key down. - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->assertNoEvents(); monitorInPrimary.assertNoEvents(); @@ -6053,7 +5996,8 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) secondWindowInPrimary->consumeFocusEvent(true); // Test inject a key down. - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->assertNoEvents(); windowInSecondary->assertNoEvents(); @@ -6068,14 +6012,14 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) { // Test touch down on primary display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT); monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT); // Test touch down on second display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID); monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID); @@ -6089,14 +6033,14 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) { // Test inject a move motion event, no window/monitor should receive the event. ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {110, 200})) << "Inject motion event should return InputEventInjectionResult::FAILED"; windowInPrimary->assertNoEvents(); monitorInPrimary.assertNoEvents(); ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {110, 200})) << "Inject motion event should return InputEventInjectionResult::FAILED"; windowInSecondary->assertNoEvents(); @@ -6239,12 +6183,7 @@ protected: InputEventInjectionSync::WAIT_FOR_RESULT, 100ms, policyFlags | additionalPolicyFlags)); - InputEvent* received = mWindow->consume(); - ASSERT_NE(nullptr, received); - ASSERT_EQ(resolvedDeviceId, received->getDeviceId()); - ASSERT_EQ(received->getType(), InputEventType::KEY); - KeyEvent& keyEvent = static_cast<KeyEvent&>(*received); - ASSERT_EQ(flags, keyEvent.getFlags()); + mWindow->consumeKeyEvent(AllOf(WithDeviceId(resolvedDeviceId), WithFlags(flags))); } void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId, @@ -6274,12 +6213,7 @@ protected: InputEventInjectionSync::WAIT_FOR_RESULT, 100ms, policyFlags | additionalPolicyFlags)); - InputEvent* received = mWindow->consume(); - ASSERT_NE(nullptr, received); - ASSERT_EQ(resolvedDeviceId, received->getDeviceId()); - ASSERT_EQ(received->getType(), InputEventType::MOTION); - MotionEvent& motionEvent = static_cast<MotionEvent&>(*received); - ASSERT_EQ(flags, motionEvent.getFlags()); + mWindow->consumeMotionEvent(AllOf(WithFlags(flags), WithDeviceId(resolvedDeviceId))); } private: @@ -6355,7 +6289,7 @@ protected: // the onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {20, 20})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mUnfocusedWindow->consumeMotionDown(); @@ -6369,7 +6303,8 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Succe // onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, {20, 20})) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, + {20, 20})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mFocusedWindow->consumeMotionDown(); @@ -6381,7 +6316,7 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPo // have focus. Ensure no window received the onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectKeyDownNoRepeat(mDispatcher, ADISPLAY_ID_DEFAULT)) + injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mFocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); @@ -6394,7 +6329,7 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMo // onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, FOCUSED_WINDOW_TOUCH_POINT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mFocusedWindow->consumeMotionDown(); @@ -6412,7 +6347,7 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) { .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20)) .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE) .build(); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, event)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, event)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mUnfocusedWindow->consumeAnyMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); @@ -6454,28 +6389,24 @@ protected: void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction, const std::vector<PointF>& points) { const std::string name = window->getName(); - InputEvent* event = window->consume(); - - ASSERT_NE(nullptr, event) << name.c_str() - << ": consumer should have returned non-NULL event."; + MotionEvent* motionEvent = window->consumeMotion(); - ASSERT_EQ(InputEventType::MOTION, event->getType()) - << name.c_str() << ": expected MotionEvent, got " << *event; + ASSERT_NE(nullptr, motionEvent) + << name.c_str() << ": consumer should have returned non-NULL event."; - const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*event); - assertMotionAction(expectedAction, motionEvent.getAction()); - ASSERT_EQ(points.size(), motionEvent.getPointerCount()); + assertMotionAction(expectedAction, motionEvent->getAction()); + ASSERT_EQ(points.size(), motionEvent->getPointerCount()); for (size_t i = 0; i < points.size(); i++) { float expectedX = points[i].x; float expectedY = points[i].y; - EXPECT_EQ(expectedX, motionEvent.getX(i)) + EXPECT_EQ(expectedX, motionEvent->getX(i)) << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str() - << ", got " << motionEvent.getX(i); - EXPECT_EQ(expectedY, motionEvent.getY(i)) + << ", got " << motionEvent->getX(i); + EXPECT_EQ(expectedY, motionEvent->getY(i)) << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str() - << ", got " << motionEvent.getY(i); + << ", got " << motionEvent->getY(i); } } @@ -6688,16 +6619,17 @@ class InputDispatcherSingleWindowAnr : public InputDispatcherTest { } protected: + static constexpr std::chrono::duration SPY_TIMEOUT = 200ms; std::shared_ptr<FakeApplicationHandle> mApplication; sp<FakeWindowHandle> mWindow; static constexpr PointF WINDOW_LOCATION = {20, 20}; void tapOnWindow() { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); } @@ -6707,7 +6639,7 @@ protected: spy->setTrustedOverlay(true); spy->setFocusable(false); spy->setSpy(true); - spy->setDispatchingTimeout(30ms); + spy->setDispatchingTimeout(SPY_TIMEOUT); mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0}); return spy; } @@ -6724,7 +6656,7 @@ TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) { // Send a regular key and respond, which should not cause an ANR. TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) { - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(mDispatcher)); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher)); mWindow->consumeKeyDown(ADISPLAY_ID_NONE); ASSERT_TRUE(mDispatcher->waitForIdle()); mFakePolicy->assertNotifyAnrWasNotCalled(); @@ -6736,8 +6668,8 @@ TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) { mWindow->consumeFocusEvent(false); InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE, /*injectionTimeout=*/50ms, + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, + InputEventInjectionSync::NONE, CONSUME_TIMEOUT_EVENT_EXPECTED, /*allowKeyRepeat=*/false); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); // Key will not go to window because we have no focused window. @@ -6756,7 +6688,7 @@ TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) { // So InputDispatcher will enqueue ACTION_CANCEL event as well. TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); std::optional<uint32_t> sequenceNum = mWindow->receiveEvent(); // ACTION_DOWN @@ -6774,7 +6706,7 @@ TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) { // Send a key to the app and have the app not respond right away. TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) { // Inject a key, and don't respond - expect that ANR is called. - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(mDispatcher)); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher)); std::optional<uint32_t> sequenceNum = mWindow->receiveEvent(); ASSERT_TRUE(sequenceNum); const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); @@ -6790,7 +6722,7 @@ TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) { // taps on the window work as normal ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown()); mDispatcher->waitForIdle(); @@ -6800,7 +6732,7 @@ TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) { // We specify the injection timeout to be smaller than the application timeout, to ensure that // injection times out (instead of failing). const InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); @@ -6851,8 +6783,8 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) // We specify the injection timeout to be smaller than the application timeout, to ensure that // injection times out (instead of failing). const InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false); + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, + InputEventInjectionSync::WAIT_FOR_RESULT, 100ms, /*allowKeyRepeat=*/false); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); const std::chrono::duration appTimeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); @@ -6874,16 +6806,13 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) { mWindow->consumeFocusEvent(false); // Once a focused event arrives, we get an ANR for this application - const InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::WAIT_FOR_RESULT, 50ms); - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); + ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher)); const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication); // Future focused events get dropped right away - ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(mDispatcher)); + ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(*mDispatcher)); ASSERT_TRUE(mDispatcher->waitForIdle()); mWindow->assertNoEvents(); } @@ -6899,14 +6828,14 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) { */ TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) { nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION, {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION}, 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime); // Now send ACTION_UP, with identical timestamp - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION, {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION}, @@ -6923,7 +6852,7 @@ TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) { sp<FakeWindowHandle> spy = addSpyWindow(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); mWindow->consumeMotionDown(); @@ -6945,9 +6874,9 @@ TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) sp<FakeWindowHandle> spy = addSpyWindow(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)); + injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT)); mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher, ADISPLAY_ID_DEFAULT)); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher, ADISPLAY_ID_DEFAULT)); // Stuck on the ACTION_UP const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); @@ -6992,19 +6921,20 @@ TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMoti } TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) { - mDispatcher->setMonitorDispatchingTimeoutForTest(30ms); + mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT); FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); const std::optional<uint32_t> consumeSeq = monitor.receiveEvent(); ASSERT_TRUE(consumeSeq); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(30ms, monitor.getToken(), MONITOR_PID); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(SPY_TIMEOUT, monitor.getToken(), + MONITOR_PID); monitor.finishEvent(*consumeSeq); monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT); @@ -7046,7 +6976,7 @@ TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) { // it. TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); @@ -7066,12 +6996,12 @@ TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) { /** * If a window is processing a motion event, and then a key event comes in, the key event should - * not to to the focused window until the motion is processed. + * not get delivered to the focused window until the motion is processed. * * Warning!!! * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT * and the injection timeout that we specify when injecting the key. - * We must have the injection timeout (10ms) be smaller than + * We must have the injection timeout (100ms) be smaller than * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms). * * If that value changes, this test should also change. @@ -7091,13 +7021,15 @@ TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) { // we will receive INJECTION_TIMED_OUT as the result. InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::WAIT_FOR_RESULT, 50ms); + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, + InputEventInjectionSync::WAIT_FOR_RESULT, 100ms); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); // Key will not be sent to the window, yet, because the window is still processing events // and the key remains pending, waiting for the touch events to be processed - std::optional<uint32_t> keySequenceNum = mWindow->receiveEvent(); - ASSERT_FALSE(keySequenceNum); + // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR. + // Rely here on the fact that it uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED under the hood. + static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms); + mWindow->assertNoEvents(); std::this_thread::sleep_for(500ms); // if we wait long enough though, dispatcher will give up, and still send the key @@ -7126,11 +7058,13 @@ TEST_F(InputDispatcherSingleWindowAnr, // Don't finish the events yet, and send a key // Injection is async, so it will succeed ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE)); + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, + ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE)); // At this point, key is still pending, and should not be sent to the application yet. - std::optional<uint32_t> keySequenceNum = mWindow->receiveEvent(); - ASSERT_FALSE(keySequenceNum); + // Make sure the `assertNoEvents` check doesn't take too long. It uses + // CONSUME_TIMEOUT_NO_EVENT_EXPECTED under the hood. + static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms); + mWindow->assertNoEvents(); // Now tap down again. It should cause the pending key to go to the focused window right away. tapOnWindow(); @@ -7242,10 +7176,10 @@ protected: private: void tap(const PointF& location) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, location)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, location)); } }; @@ -7254,7 +7188,7 @@ private: // should be ANR'd first. TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, FOCUSED_WINDOW_LOCATION)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mFocusedWindow->consumeMotionDown(); @@ -7265,7 +7199,7 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) { mFakePolicy->assertNotifyAnrWasNotCalled(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, FOCUSED_WINDOW_LOCATION)); std::optional<uint32_t> unfocusedSequenceNum = mUnfocusedWindow->receiveEvent(); ASSERT_TRUE(unfocusedSequenceNum); @@ -7346,10 +7280,10 @@ TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) { // Tap once again // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, FOCUSED_WINDOW_LOCATION)); ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, FOCUSED_WINDOW_LOCATION)); // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a // valid touch target @@ -7370,7 +7304,7 @@ TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) { // If you tap outside of all windows, there will not be ANR TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) { ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, LOCATION_OUTSIDE_ALL_WINDOWS)); ASSERT_TRUE(mDispatcher->waitForIdle()); mFakePolicy->assertNotifyAnrWasNotCalled(); @@ -7383,7 +7317,7 @@ TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) { {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, FOCUSED_WINDOW_LOCATION)); std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT)); @@ -7397,13 +7331,13 @@ TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) { /** * If a window is processing a motion event, and then a key event comes in, the key event should - * not to to the focused window until the motion is processed. + * not get delivered to the focused window until the motion is processed. * If a different window becomes focused at this time, the key should go to that window instead. * * Warning!!! * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT * and the injection timeout that we specify when injecting the key. - * We must have the injection timeout (10ms) be smaller than + * We must have the injection timeout (100ms) be smaller than * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms). * * If that value changes, this test should also change. @@ -7424,13 +7358,15 @@ TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) { // window even if motions are still being processed. InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE, /*injectionTimeout=*/50ms); + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, + InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); // Key will not be sent to the window, yet, because the window is still processing events - // and the key remains pending, waiting for the touch events to be processed - std::optional<uint32_t> keySequenceNum = mFocusedWindow->receiveEvent(); - ASSERT_FALSE(keySequenceNum); + // and the key remains pending, waiting for the touch events to be processed. + // Make sure `assertNoEvents` doesn't take too long. It uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED + // under the hood. + static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms); + mFocusedWindow->assertNoEvents(); // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there mFocusedWindow->setFocusable(false); @@ -7514,7 +7450,7 @@ TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) { TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) { std::shared_ptr<FakeApplicationHandle> focusedApplication = std::make_shared<FakeApplicationHandle>(); - focusedApplication->setDispatchingTimeout(100ms); + focusedApplication->setDispatchingTimeout(200ms); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication); // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused. mFocusedWindow->setFocusable(false); @@ -7527,8 +7463,8 @@ TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_ // 'focusedApplication' will get blamed if this timer completes. // Key will not be sent anywhere because we have no focused window. It will remain pending. InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE, /*injectionTimeout=*/50ms, + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, + InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms, /*allowKeyRepeat=*/false); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); @@ -7539,7 +7475,7 @@ TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_ // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'. // For this test, it means that the key would get delivered to the window once it becomes // focused. - std::this_thread::sleep_for(50ms); + std::this_thread::sleep_for(100ms); // Touch unfocused window. This should force the pending key to get dropped. mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, @@ -7662,7 +7598,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) { // window gets focused mWindow->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_NONE); } @@ -7674,10 +7610,10 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) { // window gets focused mWindow->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_NONE); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyUp(ADISPLAY_ID_NONE); @@ -7687,7 +7623,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) { // window loses focus since one of the windows associated with the token in not focusable mWindow->consumeFocusEvent(false); - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; mWindow->assertNoEvents(); } @@ -7699,20 +7635,20 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) { // window gets focused mWindow->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_NONE); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyUp(ADISPLAY_ID_NONE); mMirror->setVisible(false); mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_NONE); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyUp(ADISPLAY_ID_NONE); @@ -7722,7 +7658,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) { // window loses focus only after all windows associated with the token become invisible. mWindow->consumeFocusEvent(false); - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; mWindow->assertNoEvents(); } @@ -7733,20 +7669,20 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) { // window gets focused mWindow->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_NONE); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyUp(ADISPLAY_ID_NONE); // single window is removed but the window token remains focused mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0}); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_NONE); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyUp(ADISPLAY_ID_NONE); @@ -7754,7 +7690,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) { mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); mWindow->consumeFocusEvent(false); - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; mWindow->assertNoEvents(); } @@ -7769,8 +7705,8 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) { // Injected key goes to pending queue. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE)); + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, + ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE)); mMirror->setVisible(true); mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); @@ -8373,33 +8309,33 @@ protected: switch (fromSource) { case AINPUT_SOURCE_TOUCHSCREEN: ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; break; case AINPUT_SOURCE_STYLUS: ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent( - mDispatcher, - MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, - AINPUT_SOURCE_STYLUS) - .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) - .pointer(PointerBuilder(0, ToolType::STYLUS) - .x(50) - .y(50)) - .build())); + injectMotionEvent(*mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_STYLUS) + .buttonState( + AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) + .pointer(PointerBuilder(0, ToolType::STYLUS) + .x(50) + .y(50)) + .build())); break; case AINPUT_SOURCE_MOUSE: ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent( - mDispatcher, - MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) - .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(MOUSE_POINTER_ID, - ToolType::MOUSE) - .x(50) - .y(50)) - .build())); + injectMotionEvent(*mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_MOUSE) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(MOUSE_POINTER_ID, + ToolType::MOUSE) + .x(50) + .y(50)) + .build())); break; default: FAIL() << "Source " << fromSource << " doesn't support drag and drop"; @@ -8446,7 +8382,7 @@ TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) { // Move on window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8455,7 +8391,7 @@ TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) { // Move to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8464,7 +8400,7 @@ TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) { // Move back to original window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8472,7 +8408,8 @@ TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) { mSecondWindow->consumeDragEvent(true, -50, 50); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); mWindow->assertNoEvents(); @@ -8492,7 +8429,7 @@ TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -8508,7 +8445,7 @@ TEST_F(InputDispatcherDragTests, DragAndDrop) { // Move on window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8517,7 +8454,7 @@ TEST_F(InputDispatcherDragTests, DragAndDrop) { // Move to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8526,7 +8463,7 @@ TEST_F(InputDispatcherDragTests, DragAndDrop) { // drop to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); @@ -8540,7 +8477,7 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) { // Move on window and keep button pressed. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS) .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) @@ -8552,7 +8489,7 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) { // Move to another window and release button, expect to drop item. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS) .buttonState(0) .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50)) @@ -8565,7 +8502,7 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) { // nothing to the window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS) .buttonState(0) .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50)) @@ -8586,7 +8523,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) { // Move on window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8595,7 +8532,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) { // Move to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8604,7 +8541,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) { // drop to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); @@ -8618,7 +8555,7 @@ TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) { mWindow->setPreventSplitting(true); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -8631,7 +8568,7 @@ TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeMotionPointerDown(/*pointerIndex=*/1); @@ -8643,7 +8580,7 @@ TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) { TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) { // First down on second window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -8658,7 +8595,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -8674,7 +8611,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)); mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); mWindow->consumeDragEvent(false, 50, 50); @@ -8688,7 +8625,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)); mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken()); @@ -8711,7 +8648,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { // Let second display has a touch state. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(SECOND_DISPLAY_ID) @@ -8729,7 +8666,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { // Move on window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8738,7 +8675,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { // Move to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8747,7 +8684,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { // drop to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); @@ -8760,11 +8697,10 @@ TEST_F(InputDispatcherDragTests, MouseDragAndDrop) { startDrag(true, AINPUT_SOURCE_MOUSE); // Move on window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(MOUSE_POINTER_ID, - ToolType::MOUSE) + .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE) .x(50) .y(50)) .build())) @@ -8775,11 +8711,10 @@ TEST_F(InputDispatcherDragTests, MouseDragAndDrop) { // Move to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(MOUSE_POINTER_ID, - ToolType::MOUSE) + .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE) .x(150) .y(50)) .build())) @@ -8790,11 +8725,10 @@ TEST_F(InputDispatcherDragTests, MouseDragAndDrop) { // drop to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) .buttonState(0) - .pointer(PointerBuilder(MOUSE_POINTER_ID, - ToolType::MOUSE) + .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE) .x(150) .y(50)) .build())) @@ -9040,7 +8974,8 @@ TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) { // Interact with the window first. - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); @@ -9105,7 +9040,7 @@ TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) { mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); } @@ -9145,7 +9080,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) { } ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; std::vector<size_t> eventOrder; @@ -9183,7 +9118,7 @@ TEST_F(InputDispatcherSpyWindowTest, NotTouchable) { mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); spy->assertNoEvents(); @@ -9202,19 +9137,19 @@ TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) { // Inject an event outside the spy window's touchable region. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); spy->assertNoEvents(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionUp(); spy->assertNoEvents(); // Inject an event inside the spy window's touchable region. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {5, 10})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9236,7 +9171,7 @@ TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { // Inject an event outside the spy window's frame and touchable region. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9258,7 +9193,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowLeft->consumeMotionDown(); @@ -9271,7 +9206,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowRight->consumeMotionDown(); @@ -9290,7 +9225,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9303,7 +9238,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionPointerDown(/*pointerIndex=*/1); @@ -9327,7 +9262,7 @@ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { // First finger down, no window touched. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -9342,7 +9277,7 @@ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -9363,11 +9298,11 @@ TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) { setFocusedWindow(window); window->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; window->consumeKeyDown(ADISPLAY_ID_NONE); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; window->consumeKeyUp(ADISPLAY_ID_NONE); @@ -9388,7 +9323,7 @@ TEST_F(InputDispatcherPilferPointersTest, PilferPointers) { {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); spy1->consumeMotionDown(); @@ -9402,7 +9337,7 @@ TEST_F(InputDispatcherPilferPointersTest, PilferPointers) { // The rest of the gesture should only be sent to the second spy window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy2->consumeMotionMove(); @@ -9420,7 +9355,7 @@ TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -9430,7 +9365,7 @@ TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionUp(ADISPLAY_ID_DEFAULT); } @@ -9447,7 +9382,7 @@ TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) // First finger down on the window and the spy. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionDown(); @@ -9466,7 +9401,7 @@ TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -9482,7 +9417,7 @@ TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5)) .build(); ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionEvent(mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::FAILED"; @@ -9503,7 +9438,7 @@ TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) { // First finger down on the window only ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 150})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9517,7 +9452,7 @@ TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionDown(); @@ -9533,7 +9468,7 @@ TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) { .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionPointerDown(1); @@ -9563,7 +9498,7 @@ TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) { // First finger down on both spy and window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {10, 10})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9578,7 +9513,7 @@ TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionPointerDown(1); @@ -9606,7 +9541,7 @@ TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) { // First finger down on both window and spy ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {10, 10})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9625,7 +9560,7 @@ TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9777,7 +9712,7 @@ struct User { : mPid(pid), mUid(uid), mDispatcher(dispatcher) {} InputEventInjectionResult injectTargetedMotion(int32_t action) const { - return injectMotionEvent(mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN, + return injectMotionEvent(*mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200}, {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION}, @@ -9786,7 +9721,7 @@ struct User { } InputEventInjectionResult injectTargetedKey(int32_t action) const { - return inputdispatcher::injectKey(mDispatcher, action, /*repeatCount=*/0, ADISPLAY_ID_NONE, + return inputdispatcher::injectKey(*mDispatcher, action, /*repeatCount=*/0, ADISPLAY_ID_NONE, InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false, {mUid}, mPolicyFlags); @@ -9883,7 +9818,7 @@ TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTarget // A user that has injection permission can inject into any window. EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); randosSpy->consumeMotionDown(); window->consumeMotionDown(); @@ -9891,7 +9826,7 @@ TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTarget setFocusedWindow(randosSpy); randosSpy->consumeFocusEvent(true); - EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)); + EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)); randosSpy->consumeKeyDown(ADISPLAY_ID_NONE); window->assertNoEvents(); } diff --git a/services/inputflinger/tests/InstrumentedInputReader.h b/services/inputflinger/tests/InstrumentedInputReader.h index 7f8d5562ef..fef58ecfe4 100644 --- a/services/inputflinger/tests/InstrumentedInputReader.h +++ b/services/inputflinger/tests/InstrumentedInputReader.h @@ -103,12 +103,16 @@ protected: mExternalStylusDevices = devices; } + void setPreventingTouchpadTaps(bool prevent) override { mPreventingTouchpadTaps = prevent; } + bool isPreventingTouchpadTaps() override { return mPreventingTouchpadTaps; } + private: int32_t mGlobalMetaState; bool mUpdateGlobalMetaStateWasCalled; int32_t mGeneration; std::optional<nsecs_t> mRequestedTimeout; std::vector<InputDeviceInfo> mExternalStylusDevices; + bool mPreventingTouchpadTaps{false}; } mFakeContext; friend class InputReaderTest; diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h index d720a902dc..b6720c5712 100644 --- a/services/inputflinger/tests/InterfaceMocks.h +++ b/services/inputflinger/tests/InterfaceMocks.h @@ -49,6 +49,9 @@ public: MOCK_METHOD(void, updateLedMetaState, (int32_t metaState), (override)); MOCK_METHOD(int32_t, getLedMetaState, (), (override)); + + MOCK_METHOD(void, setPreventingTouchpadTaps, (bool prevent), (override)); + MOCK_METHOD(bool, isPreventingTouchpadTaps, (), (override)); }; class MockEventHubInterface : public EventHubInterface { diff --git a/services/inputflinger/tests/KeyboardInputMapper_test.cpp b/services/inputflinger/tests/KeyboardInputMapper_test.cpp new file mode 100644 index 0000000000..08a5559de4 --- /dev/null +++ b/services/inputflinger/tests/KeyboardInputMapper_test.cpp @@ -0,0 +1,152 @@ +/* + * Copyright 2023 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 "KeyboardInputMapper.h" + +#include <gtest/gtest.h> + +#include "InputMapperTest.h" +#include "InterfaceMocks.h" + +#define TAG "KeyboardInputMapper_test" + +namespace android { + +using testing::_; +using testing::DoAll; +using testing::Return; +using testing::SetArgPointee; + +/** + * Unit tests for KeyboardInputMapper. + */ +class KeyboardInputMapperUnitTest : public InputMapperUnitTest { +protected: + sp<FakeInputReaderPolicy> mFakePolicy; + const std::unordered_map<int32_t, int32_t> mKeyCodeMap{{KEY_0, AKEYCODE_0}, + {KEY_A, AKEYCODE_A}, + {KEY_LEFTCTRL, AKEYCODE_CTRL_LEFT}, + {KEY_LEFTALT, AKEYCODE_ALT_LEFT}, + {KEY_RIGHTALT, AKEYCODE_ALT_RIGHT}, + {KEY_LEFTSHIFT, AKEYCODE_SHIFT_LEFT}, + {KEY_RIGHTSHIFT, AKEYCODE_SHIFT_RIGHT}, + {KEY_FN, AKEYCODE_FUNCTION}, + {KEY_LEFTCTRL, AKEYCODE_CTRL_LEFT}, + {KEY_RIGHTCTRL, AKEYCODE_CTRL_RIGHT}, + {KEY_LEFTMETA, AKEYCODE_META_LEFT}, + {KEY_RIGHTMETA, AKEYCODE_META_RIGHT}, + {KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK}, + {KEY_NUMLOCK, AKEYCODE_NUM_LOCK}, + {KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK}}; + + void SetUp() override { + InputMapperUnitTest::SetUp(); + + // set key-codes expected in tests + for (const auto& [scanCode, outKeycode] : mKeyCodeMap) { + EXPECT_CALL(mMockEventHub, mapKey(EVENTHUB_ID, scanCode, _, _, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<4>(outKeycode), Return(NO_ERROR))); + } + + mFakePolicy = sp<FakeInputReaderPolicy>::make(); + EXPECT_CALL(mMockInputReaderContext, getPolicy).WillRepeatedly(Return(mFakePolicy.get())); + + mMapper = createInputMapper<KeyboardInputMapper>(*mDeviceContext, mReaderConfiguration, + AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); + } + + void testPointerVisibilityForKeys(const std::vector<int32_t>& keyCodes, bool expectVisible) { + EXPECT_CALL(mMockInputReaderContext, fadePointer) + .Times(expectVisible ? 0 : keyCodes.size()); + for (int32_t keyCode : keyCodes) { + process(EV_KEY, keyCode, 1); + process(EV_SYN, SYN_REPORT, 0); + process(EV_KEY, keyCode, 0); + process(EV_SYN, SYN_REPORT, 0); + } + } + + void testTouchpadTapStateForKeys(const std::vector<int32_t>& keyCodes, + const bool expectPrevent) { + EXPECT_CALL(mMockInputReaderContext, isPreventingTouchpadTaps).Times(keyCodes.size()); + if (expectPrevent) { + EXPECT_CALL(mMockInputReaderContext, setPreventingTouchpadTaps(true)) + .Times(keyCodes.size()); + } + for (int32_t keyCode : keyCodes) { + process(EV_KEY, keyCode, 1); + process(EV_SYN, SYN_REPORT, 0); + process(EV_KEY, keyCode, 0); + process(EV_SYN, SYN_REPORT, 0); + } + } +}; + +/** + * Pointer visibility should remain unaffected if there is no active Input Method Connection + */ +TEST_F(KeyboardInputMapperUnitTest, KeystrokesWithoutIMeConnectionDoesNotHidePointer) { + testPointerVisibilityForKeys({KEY_0, KEY_A, KEY_LEFTCTRL}, /* expectVisible= */ true); +} + +/** + * Pointer should hide if there is a active Input Method Connection + */ +TEST_F(KeyboardInputMapperUnitTest, AlphanumericKeystrokesWithIMeConnectionHidePointer) { + mFakePolicy->setIsInputMethodConnectionActive(true); + testPointerVisibilityForKeys({KEY_0, KEY_A}, /* expectVisible= */ false); +} + +/** + * Pointer visibility should remain unaffected by meta keys even if Input Method Connection is + * active + */ +TEST_F(KeyboardInputMapperUnitTest, MetaKeystrokesWithIMeConnectionDoesNotHidePointer) { + mFakePolicy->setIsInputMethodConnectionActive(true); + std::vector<int32_t> metaKeys{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTSHIFT, KEY_RIGHTSHIFT, + KEY_FN, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, + KEY_RIGHTMETA, KEY_CAPSLOCK, KEY_NUMLOCK, KEY_SCROLLLOCK}; + testPointerVisibilityForKeys(metaKeys, /* expectVisible= */ true); +} + +/** + * Touchpad tap should not be disabled if there is no active Input Method Connection + */ +TEST_F(KeyboardInputMapperUnitTest, KeystrokesWithoutIMeConnectionDontDisableTouchpadTap) { + testTouchpadTapStateForKeys({KEY_0, KEY_A, KEY_LEFTCTRL}, /* expectPrevent= */ false); +} + +/** + * Touchpad tap should be disabled if there is a active Input Method Connection + */ +TEST_F(KeyboardInputMapperUnitTest, AlphanumericKeystrokesWithIMeConnectionDisableTouchpadTap) { + mFakePolicy->setIsInputMethodConnectionActive(true); + testTouchpadTapStateForKeys({KEY_0, KEY_A}, /* expectPrevent= */ true); +} + +/** + * Touchpad tap should not be disabled by meta keys even if Input Method Connection is active + */ +TEST_F(KeyboardInputMapperUnitTest, MetaKeystrokesWithIMeConnectionDontDisableTouchpadTap) { + mFakePolicy->setIsInputMethodConnectionActive(true); + std::vector<int32_t> metaKeys{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTSHIFT, KEY_RIGHTSHIFT, + KEY_FN, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, + KEY_RIGHTMETA, KEY_CAPSLOCK, KEY_NUMLOCK, KEY_SCROLLLOCK}; + testTouchpadTapStateForKeys(metaKeys, /* expectPrevent= */ false); +} + +} // namespace android diff --git a/services/inputflinger/tests/TestInputListenerMatchers.cpp b/services/inputflinger/tests/TestInputListenerMatchers.cpp new file mode 100644 index 0000000000..1464e6097e --- /dev/null +++ b/services/inputflinger/tests/TestInputListenerMatchers.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2023 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 "TestInputListenerMatchers.h" + +namespace android { + +WithKeyActionMatcher WithKeyAction(int32_t action) { + return WithKeyActionMatcher(action); +} + +WithMotionActionMatcher WithMotionAction(int32_t action) { + return WithMotionActionMatcher(action); +} + +WithDisplayIdMatcher WithDisplayId(int32_t displayId) { + return WithDisplayIdMatcher(displayId); +} + +WithDeviceIdMatcher WithDeviceId(int32_t deviceId) { + return WithDeviceIdMatcher(deviceId); +} + +} // namespace android diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h index 70bad7c66b..020ea86da2 100644 --- a/services/inputflinger/tests/TestInputListenerMatchers.h +++ b/services/inputflinger/tests/TestInputListenerMatchers.h @@ -23,53 +23,145 @@ #include <gtest/gtest.h> #include <input/Input.h> +#include "NotifyArgs.h" #include "TestConstants.h" namespace android { -MATCHER_P(WithMotionAction, action, "MotionEvent with specified action") { - bool matches = action == arg.action; - if (!matches) { - *result_listener << "expected action " << MotionEvent::actionToString(action) - << ", but got " << MotionEvent::actionToString(arg.action); - } - if (action == AMOTION_EVENT_ACTION_CANCEL) { - if (!matches) { - *result_listener << "; "; - } - *result_listener << "expected FLAG_CANCELED to be set with ACTION_CANCEL, but was not set"; - matches &= (arg.flags & AMOTION_EVENT_FLAG_CANCELED) != 0; - } - return matches; -} - -MATCHER_P(WithKeyAction, action, "KeyEvent with specified action") { - *result_listener << "expected action " << KeyEvent::actionToString(action) << ", but got " - << KeyEvent::actionToString(arg.action); - return arg.action == action; -} - MATCHER_P(WithSource, source, "InputEvent with specified source") { *result_listener << "expected source " << inputEventSourceToString(source) << ", but got " << inputEventSourceToString(arg.source); return arg.source == source; } -MATCHER_P(WithDisplayId, displayId, "InputEvent with specified displayId") { - *result_listener << "expected displayId " << displayId << ", but got " << arg.displayId; - return arg.displayId == displayId; -} +/// Key action +class WithKeyActionMatcher { +public: + using is_gtest_matcher = void; + explicit WithKeyActionMatcher(int32_t action) : mAction(action) {} -MATCHER_P(WithDeviceId, deviceId, "InputEvent with specified deviceId") { - *result_listener << "expected deviceId " << deviceId << ", but got " << arg.deviceId; - return arg.deviceId == deviceId; -} + bool MatchAndExplain(const NotifyKeyArgs& args, std::ostream*) const { + return mAction == args.action; + } + + bool MatchAndExplain(const KeyEvent& event, std::ostream*) const { + return mAction == event.getAction(); + } + + void DescribeTo(std::ostream* os) const { + *os << "with key action " << KeyEvent::actionToString(mAction); + } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong action"; } + +private: + const int32_t mAction; +}; + +WithKeyActionMatcher WithKeyAction(int32_t action); + +/// Motion action +class WithMotionActionMatcher { +public: + using is_gtest_matcher = void; + explicit WithMotionActionMatcher(int32_t action) : mAction(action) {} + + bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const { + bool matches = mAction == args.action; + if (args.action == AMOTION_EVENT_ACTION_CANCEL) { + matches &= (args.flags & AMOTION_EVENT_FLAG_CANCELED) != 0; + } + return matches; + } + + bool MatchAndExplain(const MotionEvent& event, std::ostream*) const { + bool matches = mAction == event.getAction(); + if (event.getAction() == AMOTION_EVENT_ACTION_CANCEL) { + matches &= (event.getFlags() & AMOTION_EVENT_FLAG_CANCELED) != 0; + } + return matches; + } + + void DescribeTo(std::ostream* os) const { + *os << "with motion action " << MotionEvent::actionToString(mAction); + if (mAction == AMOTION_EVENT_ACTION_CANCEL) { + *os << " and FLAG_CANCELED"; + } + } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong action"; } + +private: + const int32_t mAction; +}; + +WithMotionActionMatcher WithMotionAction(int32_t action); + +/// Display Id +class WithDisplayIdMatcher { +public: + using is_gtest_matcher = void; + explicit WithDisplayIdMatcher(int32_t displayId) : mDisplayId(displayId) {} + + bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const { + return mDisplayId == args.displayId; + } + + bool MatchAndExplain(const NotifyKeyArgs& args, std::ostream*) const { + return mDisplayId == args.displayId; + } + + bool MatchAndExplain(const InputEvent& event, std::ostream*) const { + return mDisplayId == event.getDisplayId(); + } + + void DescribeTo(std::ostream* os) const { *os << "with display id " << mDisplayId; } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong display id"; } + +private: + const int32_t mDisplayId; +}; + +WithDisplayIdMatcher WithDisplayId(int32_t displayId); + +/// Device Id +class WithDeviceIdMatcher { +public: + using is_gtest_matcher = void; + explicit WithDeviceIdMatcher(int32_t deviceId) : mDeviceId(deviceId) {} + + bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const { + return mDeviceId == args.deviceId; + } + + bool MatchAndExplain(const NotifyKeyArgs& args, std::ostream*) const { + return mDeviceId == args.deviceId; + } + + bool MatchAndExplain(const InputEvent& event, std::ostream*) const { + return mDeviceId == event.getDeviceId(); + } + + void DescribeTo(std::ostream* os) const { *os << "with device id " << mDeviceId; } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong device id"; } + +private: + const int32_t mDeviceId; +}; + +WithDeviceIdMatcher WithDeviceId(int32_t deviceId); MATCHER_P(WithKeyCode, keyCode, "KeyEvent with specified key code") { *result_listener << "expected key code " << keyCode << ", but got " << arg.keyCode; return arg.keyCode == keyCode; } +MATCHER_P(WithRepeatCount, repeatCount, "KeyEvent with specified repeat count") { + return arg.getRepeatCount() == repeatCount; +} + MATCHER_P(WithPointerCount, count, "MotionEvent with specified number of pointers") { *result_listener << "expected " << count << " pointer(s), but got " << arg.getPointerCount(); return arg.getPointerCount() == count; diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index e88731aafd..bdedfdfa0c 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -295,7 +295,8 @@ public: } void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override {} std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( - const InputDeviceIdentifier& identifier) override { + const InputDeviceIdentifier& identifier, + const std::optional<KeyboardLayoutInfo> layoutInfo) override { return nullptr; } std::string getDeviceAlias(const InputDeviceIdentifier& identifier) { @@ -307,6 +308,7 @@ public: } void setTouchAffineTransformation(const TouchAffineTransformation t) { mTransform = t; } void notifyStylusGestureStarted(int32_t, nsecs_t) {} + bool isInputMethodConnectionActive() override { return mFdp->ConsumeBool(); } }; class FuzzInputListener : public virtual InputListenerInterface { @@ -355,6 +357,9 @@ public: void updateLedMetaState(int32_t metaState) override{}; int32_t getLedMetaState() override { return mFdp->ConsumeIntegral<int32_t>(); }; void notifyStylusGestureStarted(int32_t, nsecs_t) {} + + void setPreventingTouchpadTaps(bool prevent) {} + bool isPreventingTouchpadTaps() { return mFdp->ConsumeBool(); }; }; template <class Fdp> diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index 09bc46747a..1a8644e9fe 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -67,9 +67,6 @@ struct CompositionRefreshArgs { // Controls how the color mode is chosen for an output OutputColorSetting outputColorSetting{OutputColorSetting::kEnhanced}; - // If not Dataspace::UNKNOWN, overrides the dataspace on each output - ui::Dataspace colorSpaceAgnosticDataspace{ui::Dataspace::UNKNOWN}; - // Forces a color mode on the outputs being refreshed ui::ColorMode forceOutputColorMode{ui::ColorMode::NATIVE}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h index df44e75625..9c80cacf6f 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h @@ -87,10 +87,6 @@ public: // Returns true if HWC for this profile supports the dataspace virtual bool isDataspaceSupported(ui::Dataspace) const = 0; - // Returns the target dataspace for picked color mode and dataspace - virtual ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace, - ui::Dataspace colorSpaceAgnosticDataspace) const = 0; - // Debugging virtual void dump(std::string&) const = 0; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index a3d86398cf..370c7cf223 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -136,7 +136,6 @@ public: ui::ColorMode mode{ui::ColorMode::NATIVE}; ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC}; - ui::Dataspace colorSpaceAgnosticDataspace{ui::Dataspace::UNKNOWN}; }; // Use internally to incrementally compute visibility/coverage diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h index 9bc0e681c7..3aad04c1a3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h @@ -55,7 +55,6 @@ public: const HdrCapabilities& getHdrCapabilities() const override; bool isDataspaceSupported(ui::Dataspace) const override; - ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace) const override; void dump(std::string&) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 28c6e92b06..6cb1e7e4c2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -116,9 +116,6 @@ struct OutputCompositionState { // Current active dataspace ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; - // Current target dataspace - ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN}; - std::optional<android::HWComposer::DeviceRequestedChanges> previousDeviceRequestedChanges{}; bool previousDeviceRequestedSuccess = false; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h index 1aaebea295..a9045211af 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h @@ -43,8 +43,6 @@ public: MOCK_CONST_METHOD0(getHdrCapabilities, const HdrCapabilities&()); MOCK_CONST_METHOD1(isDataspaceSupported, bool(ui::Dataspace)); - MOCK_CONST_METHOD3(getTargetDataspace, - ui::Dataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace)); MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 85fc09549b..f2acfc9e6e 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -107,14 +107,9 @@ void Display::setColorTransform(const compositionengine::CompositionRefreshArgs& } void Display::setColorProfile(const ColorProfile& colorProfile) { - const ui::Dataspace targetDataspace = - getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace, - colorProfile.colorSpaceAgnosticDataspace); - if (colorProfile.mode == getState().colorMode && colorProfile.dataspace == getState().dataspace && - colorProfile.renderIntent == getState().renderIntent && - targetDataspace == getState().targetDataspace) { + colorProfile.renderIntent == getState().renderIntent) { return; } diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp index a7c45129b1..8f67f3683a 100644 --- a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp @@ -391,17 +391,6 @@ bool DisplayColorProfile::isDataspaceSupported(Dataspace dataspace) const { } } -ui::Dataspace DisplayColorProfile::getTargetDataspace(ColorMode mode, Dataspace dataspace, - Dataspace colorSpaceAgnosticDataspace) const { - if (isHdrColorMode(mode)) { - return Dataspace::UNKNOWN; - } - if (colorSpaceAgnosticDataspace != ui::Dataspace::UNKNOWN) { - return colorSpaceAgnosticDataspace; - } - return dataspace; -} - void DisplayColorProfile::dump(std::string& out) const { out.append(" Composition Display Color State:"); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index b1b5708473..d4230f5575 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -261,22 +261,16 @@ void Output::setColorTransform(const compositionengine::CompositionRefreshArgs& } void Output::setColorProfile(const ColorProfile& colorProfile) { - ui::Dataspace targetDataspace = - getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace, - colorProfile.colorSpaceAgnosticDataspace); - auto& outputState = editState(); if (outputState.colorMode == colorProfile.mode && outputState.dataspace == colorProfile.dataspace && - outputState.renderIntent == colorProfile.renderIntent && - outputState.targetDataspace == targetDataspace) { + outputState.renderIntent == colorProfile.renderIntent) { return; } outputState.colorMode = colorProfile.mode; outputState.dataspace = colorProfile.dataspace; outputState.renderIntent = colorProfile.renderIntent; - outputState.targetDataspace = targetDataspace; mRenderSurface->setBufferDataspace(colorProfile.dataspace); @@ -984,8 +978,7 @@ compositionengine::Output::ColorProfile Output::pickColorProfile( const compositionengine::CompositionRefreshArgs& refreshArgs) const { if (refreshArgs.outputColorSetting == OutputColorSetting::kUnmanaged) { return ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, - ui::RenderIntent::COLORIMETRIC, - refreshArgs.colorSpaceAgnosticDataspace}; + ui::RenderIntent::COLORIMETRIC}; } ui::Dataspace hdrDataSpace; @@ -1031,8 +1024,7 @@ compositionengine::Output::ColorProfile Output::pickColorProfile( mDisplayColorProfile->getBestColorMode(bestDataSpace, intent, &outDataSpace, &outMode, &outRenderIntent); - return ColorProfile{outMode, outDataSpace, outRenderIntent, - refreshArgs.colorSpaceAgnosticDataspace}; + return ColorProfile{outMode, outDataSpace, outRenderIntent}; } void Output::beginFrame() { diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index 9713e79fe3..39cf67165a 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -52,7 +52,6 @@ void OutputCompositionState::dump(std::string& out) const { dumpVal(out, "colorMode", toString(colorMode), colorMode); dumpVal(out, "renderIntent", toString(renderIntent), renderIntent); dumpVal(out, "dataspace", toString(dataspace), dataspace); - dumpVal(out, "targetDataspace", toString(targetDataspace), targetDataspace); out.append("\n "); dumpVal(out, "colorTransformMatrix", colorTransformMatrix); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 0ac0ecb727..b492b6a79e 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -315,9 +315,10 @@ void OutputLayer::updateCompositionState( // Determine the output dependent dataspace for this layer. If it is // colorspace agnostic, it just uses the dataspace chosen for the output to // avoid the need for color conversion. - state.dataspace = layerFEState->isColorspaceAgnostic && - outputState.targetDataspace != ui::Dataspace::UNKNOWN - ? outputState.targetDataspace + // For now, also respect the colorspace agnostic flag if we're drawing to HDR, to avoid drastic + // luminance shift. TODO(b/292162273): we should check if that's true though. + state.dataspace = layerFEState->isColorspaceAgnostic && !isHdrDataspace(outputState.dataspace) + ? outputState.dataspace : layerFEState->dataspace; // Override the dataspace transfer from 170M to sRGB if the device configuration requests this. diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp index 21b9aa93ea..b3ff2ec6a0 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp @@ -646,29 +646,5 @@ TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithHlgSuppor EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG)); } -/* - * RenderSurface::getTargetDataspace() - */ - -TEST_F(DisplayColorProfileTest, getTargetDataspaceWorks) { - auto profile = ProfileFactory::createProfileWithNoColorModeSupport(); - - // For a non-HDR colorspace with no colorSpaceAgnosticDataspace override, - // the input dataspace should be returned. - EXPECT_EQ(Dataspace::DISPLAY_P3, - profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3, - Dataspace::UNKNOWN)); - - // If colorSpaceAgnosticDataspace is set, its value should be returned - EXPECT_EQ(Dataspace::V0_SRGB, - profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3, - Dataspace::V0_SRGB)); - - // For an HDR colorspace, Dataspace::UNKNOWN should be returned. - EXPECT_EQ(Dataspace::UNKNOWN, - profile.getTargetDataspace(ColorMode::BT2100_PQ, Dataspace::BT2020_PQ, - Dataspace::UNKNOWN)); -} - } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 9be6bc2075..027004acf6 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -403,23 +403,18 @@ TEST_F(DisplaySetColorModeTest, setsModeUnlessNoChange) { mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>(); mDisplay->setDisplayColorProfileForTest(std::unique_ptr<DisplayColorProfile>(colorProfile)); - EXPECT_CALL(*colorProfile, getTargetDataspace(_, _, _)) - .WillRepeatedly(Return(ui::Dataspace::UNKNOWN)); - // These values are expected to be the initial state. ASSERT_EQ(ui::ColorMode::NATIVE, mDisplay->getState().colorMode); ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().dataspace); ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay->getState().renderIntent); - ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace); // Otherwise if the values are unchanged, nothing happens mDisplay->setColorProfile(ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, - ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN}); + ui::RenderIntent::COLORIMETRIC}); EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay->getState().colorMode); EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().dataspace); EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay->getState().renderIntent); - EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace); // Otherwise if the values are different, updates happen EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1); @@ -429,13 +424,11 @@ TEST_F(DisplaySetColorModeTest, setsModeUnlessNoChange) { .Times(1); mDisplay->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, - ui::Dataspace::UNKNOWN}); + ui::RenderIntent::TONE_MAP_COLORIMETRIC}); EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mDisplay->getState().colorMode); EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mDisplay->getState().dataspace); EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay->getState().renderIntent); - EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace); } TEST_F(DisplaySetColorModeTest, doesNothingForVirtualDisplay) { @@ -448,19 +441,13 @@ TEST_F(DisplaySetColorModeTest, doesNothingForVirtualDisplay) { virtualDisplay->setDisplayColorProfileForTest( std::unique_ptr<DisplayColorProfile>(colorProfile)); - EXPECT_CALL(*colorProfile, - getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::Dataspace::UNKNOWN)) - .WillOnce(Return(ui::Dataspace::UNKNOWN)); - - virtualDisplay->setColorProfile( - ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN}); + virtualDisplay->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, + ui::Dataspace::DISPLAY_P3, + ui::RenderIntent::TONE_MAP_COLORIMETRIC}); EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay->getState().colorMode); EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay->getState().dataspace); EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay->getState().renderIntent); - EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay->getState().targetDataspace); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index aa83883e95..9039d16aeb 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -642,7 +642,7 @@ TEST_F(OutputLayerUpdateCompositionStateTest, TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceCorrectly) { mLayerFEState.dataspace = ui::Dataspace::DISPLAY_P3; - mOutputState.targetDataspace = ui::Dataspace::V0_SCRGB; + mOutputState.dataspace = ui::Dataspace::V0_SCRGB; // If the layer is not colorspace agnostic, the output layer dataspace // should use the layers requested colorspace. @@ -659,11 +659,18 @@ TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceCorrectly mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0); EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace); + + // If the output is HDR, then don't blind the user with a colorspace agnostic dataspace + // drawing all white + mOutputState.dataspace = ui::Dataspace::BT2020_PQ; + + mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0); + + EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutputLayer.getState().dataspace); } TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceWith170mReplacement) { mLayerFEState.dataspace = ui::Dataspace::TRANSFER_SMPTE_170M; - mOutputState.targetDataspace = ui::Dataspace::V0_SCRGB; mOutputState.treat170mAsSrgb = false; mLayerFEState.isColorspaceAgnostic = false; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 9e0e7b5a53..ebf9a2b2e2 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -175,12 +175,10 @@ const Rect OutputTest::kDefaultDisplaySize{100, 200}; using ColorProfile = compositionengine::Output::ColorProfile; void dumpColorProfile(ColorProfile profile, std::string& result, const char* name) { - android::base::StringAppendF(&result, "%s (%s[%d] %s[%d] %s[%d] %s[%d]) ", name, + android::base::StringAppendF(&result, "%s (%s[%d] %s[%d] %s[%d]) ", name, toString(profile.mode).c_str(), profile.mode, toString(profile.dataspace).c_str(), profile.dataspace, - toString(profile.renderIntent).c_str(), profile.renderIntent, - toString(profile.colorSpaceAgnosticDataspace).c_str(), - profile.colorSpaceAgnosticDataspace); + toString(profile.renderIntent).c_str(), profile.renderIntent); } // Checks for a ColorProfile match @@ -192,8 +190,7 @@ MATCHER_P(ColorProfileEq, expected, "") { *result_listener << buf; return (expected.mode == arg.mode) && (expected.dataspace == arg.dataspace) && - (expected.renderIntent == arg.renderIntent) && - (expected.colorSpaceAgnosticDataspace == arg.colorSpaceAgnosticDataspace); + (expected.renderIntent == arg.renderIntent); } /* @@ -540,20 +537,14 @@ using OutputSetColorProfileTest = OutputTest; TEST_F(OutputSetColorProfileTest, setsStateAndDirtiesOutputIfChanged) { using ColorProfile = Output::ColorProfile; - EXPECT_CALL(*mDisplayColorProfile, - getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::Dataspace::UNKNOWN)) - .WillOnce(Return(ui::Dataspace::UNKNOWN)); EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1); mOutput->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, - ui::Dataspace::UNKNOWN}); + ui::RenderIntent::TONE_MAP_COLORIMETRIC}); EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput->getState().colorMode); EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput->getState().dataspace); EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput->getState().renderIntent); - EXPECT_EQ(ui::Dataspace::UNKNOWN, mOutput->getState().targetDataspace); EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } @@ -561,19 +552,12 @@ TEST_F(OutputSetColorProfileTest, setsStateAndDirtiesOutputIfChanged) { TEST_F(OutputSetColorProfileTest, doesNothingIfNoChange) { using ColorProfile = Output::ColorProfile; - EXPECT_CALL(*mDisplayColorProfile, - getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::Dataspace::UNKNOWN)) - .WillOnce(Return(ui::Dataspace::UNKNOWN)); - mOutput->editState().colorMode = ui::ColorMode::DISPLAY_P3; mOutput->editState().dataspace = ui::Dataspace::DISPLAY_P3; mOutput->editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC; - mOutput->editState().targetDataspace = ui::Dataspace::UNKNOWN; mOutput->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, - ui::Dataspace::UNKNOWN}); + ui::RenderIntent::TONE_MAP_COLORIMETRIC}); EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region())); } @@ -2133,12 +2117,11 @@ TEST_F(OutputUpdateColorProfileTest, setsAColorProfileWhenUnmanaged) { EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3u)); EXPECT_CALL(mOutput, - setColorProfile(ColorProfileEq( - ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, - ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN}))); + setColorProfile( + ColorProfileEq(ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, + ui::RenderIntent::COLORIMETRIC}))); mRefreshArgs.outputColorSetting = OutputColorSetting::kUnmanaged; - mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; mOutput.updateColorProfile(mRefreshArgs); } @@ -2148,7 +2131,6 @@ struct OutputUpdateColorProfileTest_GetBestColorModeResultBecomesSetProfile OutputUpdateColorProfileTest_GetBestColorModeResultBecomesSetProfile() { EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced; - mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; } struct ExpectBestColorModeCallResultUsedToSetColorProfileState @@ -2163,8 +2145,7 @@ struct OutputUpdateColorProfileTest_GetBestColorModeResultBecomesSetProfile SetArgPointee<4>(renderIntent))); EXPECT_CALL(getInstance()->mOutput, setColorProfile( - ColorProfileEq(ColorProfile{colorMode, dataspace, renderIntent, - ui::Dataspace::UNKNOWN}))); + ColorProfileEq(ColorProfile{colorMode, dataspace, renderIntent}))); return nextState<ExecuteState>(); } }; @@ -2191,55 +2172,6 @@ TEST_F(OutputUpdateColorProfileTest_GetBestColorModeResultBecomesSetProfile, .execute(); } -struct OutputUpdateColorProfileTest_ColorSpaceAgnosticeDataspaceAffectsSetColorProfile - : public OutputUpdateColorProfileTest { - OutputUpdateColorProfileTest_ColorSpaceAgnosticeDataspaceAffectsSetColorProfile() { - EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); - EXPECT_CALL(*mDisplayColorProfile, - getBestColorMode(ui::Dataspace::V0_SRGB, ui::RenderIntent::ENHANCE, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<2>(ui::Dataspace::UNKNOWN), - SetArgPointee<3>(ui::ColorMode::NATIVE), - SetArgPointee<4>(ui::RenderIntent::COLORIMETRIC))); - mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced; - } - - struct IfColorSpaceAgnosticDataspaceSetToState - : public CallOrderStateMachineHelper<TestType, IfColorSpaceAgnosticDataspaceSetToState> { - [[nodiscard]] auto ifColorSpaceAgnosticDataspaceSetTo(ui::Dataspace dataspace) { - getInstance()->mRefreshArgs.colorSpaceAgnosticDataspace = dataspace; - return nextState<ThenExpectSetColorProfileCallUsesColorSpaceAgnosticDataspaceState>(); - } - }; - - struct ThenExpectSetColorProfileCallUsesColorSpaceAgnosticDataspaceState - : public CallOrderStateMachineHelper< - TestType, ThenExpectSetColorProfileCallUsesColorSpaceAgnosticDataspaceState> { - [[nodiscard]] auto thenExpectSetColorProfileCallUsesColorSpaceAgnosticDataspace( - ui::Dataspace dataspace) { - EXPECT_CALL(getInstance()->mOutput, - setColorProfile(ColorProfileEq( - ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, - ui::RenderIntent::COLORIMETRIC, dataspace}))); - return nextState<ExecuteState>(); - } - }; - - // Call this member function to start using the mini-DSL defined above. - [[nodiscard]] auto verify() { return IfColorSpaceAgnosticDataspaceSetToState::make(this); } -}; - -TEST_F(OutputUpdateColorProfileTest_ColorSpaceAgnosticeDataspaceAffectsSetColorProfile, DisplayP3) { - verify().ifColorSpaceAgnosticDataspaceSetTo(ui::Dataspace::DISPLAY_P3) - .thenExpectSetColorProfileCallUsesColorSpaceAgnosticDataspace(ui::Dataspace::DISPLAY_P3) - .execute(); -} - -TEST_F(OutputUpdateColorProfileTest_ColorSpaceAgnosticeDataspaceAffectsSetColorProfile, V0_SRGB) { - verify().ifColorSpaceAgnosticDataspaceSetTo(ui::Dataspace::V0_SRGB) - .thenExpectSetColorProfileCallUsesColorSpaceAgnosticDataspace(ui::Dataspace::V0_SRGB) - .execute(); -} - struct OutputUpdateColorProfileTest_TopmostLayerPreferenceSetsOutputPreference : public OutputUpdateColorProfileTest { // Internally the implementation looks through the dataspaces of all the @@ -2248,7 +2180,6 @@ struct OutputUpdateColorProfileTest_TopmostLayerPreferenceSetsOutputPreference OutputUpdateColorProfileTest_TopmostLayerPreferenceSetsOutputPreference() { mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced; - mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3u)); EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return()); @@ -2368,7 +2299,6 @@ struct OutputUpdateColorProfileTest_ForceOutputColorOverrides OutputUpdateColorProfileTest_ForceOutputColorOverrides() { mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced; - mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; mLayer1.mLayerFEState.dataspace = ui::Dataspace::DISPLAY_BT2020; @@ -2424,7 +2354,6 @@ TEST_F(OutputUpdateColorProfileTest_ForceOutputColorOverrides, DisplayP3_Overrid struct OutputUpdateColorProfileTest_Hdr : public OutputUpdateColorProfileTest { OutputUpdateColorProfileTest_Hdr() { mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced; - mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(2u)); EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return()); } @@ -2703,7 +2632,6 @@ struct OutputUpdateColorProfile_AffectsChosenRenderIntentTest OutputUpdateColorProfile_AffectsChosenRenderIntentTest() { mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced; - mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; mLayer1.mLayerFEState.dataspace = ui::Dataspace::BT2020_PQ; EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u)); EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return()); diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index 2529095f99..fb985f7c5b 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -302,6 +302,19 @@ float RefreshRateSelector::calculateNonExactMatchingLayerScoreLocked(const Layer if (layer.vote == LayerVoteType::ExplicitExactOrMultiple || layer.vote == LayerVoteType::Heuristic) { + using fps_approx_ops::operator<; + if (refreshRate < 60_Hz) { + const bool favorsAtLeast60 = + std::find_if(mFrameRatesThatFavorsAtLeast60.begin(), + mFrameRatesThatFavorsAtLeast60.end(), [&](Fps fps) { + using fps_approx_ops::operator==; + return fps == layer.desiredRefreshRate; + }) != mFrameRatesThatFavorsAtLeast60.end(); + if (favorsAtLeast60) { + return 0; + } + } + const float multiplier = refreshRate.getValue() / layer.desiredRefreshRate.getValue(); // We only want to score this layer as a fractional pair if the content is not diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h index 5052e6e257..7af8d0397f 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -18,6 +18,7 @@ #include <algorithm> #include <numeric> +#include <set> #include <type_traits> #include <utility> #include <variant> @@ -500,6 +501,12 @@ private: const std::vector<Fps> mKnownFrameRates; const Config mConfig; + + // A list of known frame rates that favors at least 60Hz if there is no exact match display + // refresh rate + const std::vector<Fps> mFrameRatesThatFavorsAtLeast60 = {23.976_Hz, 25_Hz, 29.97_Hz, 50_Hz, + 59.94_Hz}; + Config::FrameRateOverride mFrameRateOverrideConfig; struct GetRankedFrameRatesCache { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index fda8d689a5..9de623fff9 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -406,9 +406,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI wideColorGamutCompositionPixelFormat = static_cast<ui::PixelFormat>(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888)); - mColorSpaceAgnosticDataspace = - static_cast<ui::Dataspace>(color_space_agnostic_dataspace(Dataspace::UNKNOWN)); - mLayerCachingEnabled = [] { const bool enable = android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false); @@ -1526,7 +1523,7 @@ status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ui: } display->getCompositionDisplay()->setColorProfile( - {mode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); + {mode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC}); return NO_ERROR; }); @@ -2609,7 +2606,6 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( refreshArgs.outputColorSetting = useColorManagement ? mDisplayColorSetting : compositionengine::OutputColorSetting::kUnmanaged; - refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace; refreshArgs.forceOutputColorMode = mForceColorMode; refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty; @@ -3421,8 +3417,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( } display->getCompositionDisplay()->setColorProfile( compositionengine::Output::ColorProfile{defaultColorMode, defaultDataSpace, - RenderIntent::COLORIMETRIC, - Dataspace::UNKNOWN}); + RenderIntent::COLORIMETRIC}); if (const auto& physical = state.physical) { mPhysicalDisplays.get(physical->id) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index d1b6660063..4374f9408f 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1303,7 +1303,6 @@ private: ui::Dataspace mDefaultCompositionDataspace; ui::Dataspace mWideColorGamutCompositionDataspace; - ui::Dataspace mColorSpaceAgnosticDataspace; std::unique_ptr<renderengine::RenderEngine> mRenderEngine; std::atomic<int> mNumTrustedPresentationListeners = 0; diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 96c8b54005..66c8f33fe5 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -227,14 +227,6 @@ int32_t wcg_composition_pixel_format(PixelFormat defaultValue) { return static_cast<int32_t>(defaultValue); } -int64_t color_space_agnostic_dataspace(Dataspace defaultValue) { - auto temp = SurfaceFlingerProperties::color_space_agnostic_dataspace(); - if (temp.has_value()) { - return *temp; - } - return static_cast<int64_t>(defaultValue); -} - bool refresh_rate_switching(bool defaultValue) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index 951f8f8cb3..a08042009b 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -71,9 +71,6 @@ int64_t wcg_composition_dataspace( int32_t wcg_composition_pixel_format( android::hardware::graphics::common::V1_2::PixelFormat defaultValue); -int64_t color_space_agnostic_dataspace( - android::hardware::graphics::common::V1_2::Dataspace defaultValue); - bool refresh_rate_switching(bool defaultValue); int32_t set_idle_timer_ms(int32_t defaultValue); diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index 5cac086c21..be29be4ef4 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -199,6 +199,7 @@ prop { # useColorManagement indicates whether SurfaceFlinger should manage color # by switching to appropriate color mode automatically depending on the # Dataspace of the surfaces on screen. +# DEPRECATED: SurfaceFlinger is always color managed. prop { api_name: "use_color_management" type: Boolean @@ -207,7 +208,7 @@ prop { prop_name: "ro.surface_flinger.use_color_management" } -# The following four propertiess define: +# The following four properties define: # Returns the default data space and pixel format that SurfaceFlinger # expects to receive and output as well as the wide color gamut data space # and pixel format for wide color gamut surfaces. @@ -276,7 +277,7 @@ prop { # The variable works only when useColorManagement is specified. If # unspecified, the data space follows what SurfaceFlinger expects for # surfaces when useColorManagement is specified. - +# DEPRECATED: do not use prop { api_name: "color_space_agnostic_dataspace" type: Long diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp index cbd54e7aa9..03de8d0b6d 100644 --- a/services/surfaceflinger/tests/LayerTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp @@ -184,6 +184,35 @@ TEST_F(LayerTransactionTest, BufferTakesPriorityOverColor) { } } +TEST_F(LayerTransactionTest, CommitCallbackCalledOnce) { + auto callCount = 0; + auto commitCallback = + [&callCount](void* /* context */, nsecs_t /* latchTime */, + const sp<Fence>& /* presentFence */, + const std::vector<SurfaceControlStats>& /* stats */) mutable { + callCount++; + }; + + // Create two transactions that both contain the same callback id. + Transaction t1; + t1.addTransactionCommittedCallback(commitCallback, nullptr); + Parcel parcel; + t1.writeToParcel(&parcel); + parcel.setDataPosition(0); + Transaction t2; + t2.readFromParcel(&parcel); + + // Apply the two transactions. There is a race here as we can't guarantee that the two + // transactions will be applied within the same SurfaceFlinger commit. If the transactions are + // applied within the same commit then we verify that callback ids are deduplicated within a + // single commit. Otherwise, we verify that commit callbacks are deduplicated across separate + // commits. + t1.apply(); + t2.apply(/*synchronous=*/true); + + ASSERT_EQ(callCount, 1); +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index 646d9cc0a0..aaf55fbeae 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -222,6 +222,7 @@ protected: makeModes(kMode60, kMode90, kMode72_G1, kMode120_G1, kMode30_G1, kMode25_G1, kMode50); static inline const DisplayModes kModes_60_120 = makeModes(kMode60, kMode120); static inline const DisplayModes kModes_1_5_10 = makeModes(kMode1, kMode5, kMode10); + static inline const DisplayModes kModes_60_90_120 = makeModes(kMode60, kMode90, kMode120); // This is a typical TV configuration. static inline const DisplayModes kModes_24_25_30_50_60_Frac = @@ -1413,7 +1414,9 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitDefault) { ss << "ExplicitDefault " << desired; lr.name = ss.str(); - EXPECT_EQ(expected, selector.getBestFrameRateMode(layers)->getFps()); + const auto bestFps = selector.getBestFrameRateMode(layers)->getFps(); + EXPECT_EQ(expected, bestFps) + << "expected " << expected << " for " << desired << " but got " << bestFps; } } @@ -1422,7 +1425,7 @@ TEST_P(RefreshRateSelectorTest, std::vector<LayerRequirement> layers = {{.weight = 1.f}}; auto& lr = layers[0]; - // Test that 23.976 will choose 24 if 23.976 is not supported + // Test that 23.976 will prefer 60 over 59.94 and 30 { auto selector = createSelector(makeModes(kMode24, kMode25, kMode30, kMode30Frac, kMode60, kMode60Frac), @@ -1431,7 +1434,7 @@ TEST_P(RefreshRateSelectorTest, lr.vote = LayerVoteType::ExplicitExactOrMultiple; lr.desiredRefreshRate = 23.976_Hz; lr.name = "ExplicitExactOrMultiple 23.976 Hz"; - EXPECT_EQ(kModeId24, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); } // Test that 24 will choose 23.976 if 24 is not supported @@ -1456,13 +1459,13 @@ TEST_P(RefreshRateSelectorTest, EXPECT_EQ(kModeId60Frac, selector.getBestFrameRateMode(layers)->getId()); } - // Test that 29.97 will choose 30 if 59.94 is not supported + // Test that 29.97 will choose 60 if 59.94 is not supported { auto selector = createSelector(makeModes(kMode30, kMode60), kModeId60); lr.desiredRefreshRate = 29.97_Hz; lr.name = "ExplicitExactOrMultiple 29.97 Hz"; - EXPECT_EQ(kModeId30, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); } // Test that 59.94 will choose 60 if 59.94 is not supported @@ -2516,6 +2519,71 @@ TEST_P(RefreshRateSelectorTest, isFractionalPairOrMultiple) { EXPECT_FALSE(RefreshRateSelector::isFractionalPairOrMultiple(29.97_Hz, 59.94_Hz)); } +TEST_P(RefreshRateSelectorTest, test23976Chooses120) { + auto selector = createSelector(kModes_60_90_120, kModeId120); + std::vector<LayerRequirement> layers = {{.weight = 1.f}}; + layers[0].name = "23.976 ExplicitExactOrMultiple"; + layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; + layers[0].desiredRefreshRate = 23.976_Hz; + EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, selector.getBestScoredFrameRate(layers).frameRateMode); +} + +TEST_P(RefreshRateSelectorTest, test23976Chooses60IfThresholdIs120) { + auto selector = + createSelector(kModes_60_90_120, kModeId120, {.frameRateMultipleThreshold = 120}); + std::vector<LayerRequirement> layers = {{.weight = 1.f}}; + layers[0].name = "23.976 ExplicitExactOrMultiple"; + layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; + layers[0].desiredRefreshRate = 23.976_Hz; + EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode); +} + +TEST_P(RefreshRateSelectorTest, test25Chooses60) { + auto selector = createSelector(kModes_60_90_120, kModeId120); + std::vector<LayerRequirement> layers = {{.weight = 1.f}}; + layers[0].name = "25 ExplicitExactOrMultiple"; + layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; + layers[0].desiredRefreshRate = 25.00_Hz; + EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode); +} + +TEST_P(RefreshRateSelectorTest, test2997Chooses60) { + auto selector = createSelector(kModes_60_90_120, kModeId120); + std::vector<LayerRequirement> layers = {{.weight = 1.f}}; + layers[0].name = "29.97 ExplicitExactOrMultiple"; + layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; + layers[0].desiredRefreshRate = 29.97_Hz; + EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode); +} + +TEST_P(RefreshRateSelectorTest, test50Chooses120) { + auto selector = createSelector(kModes_60_90_120, kModeId120); + std::vector<LayerRequirement> layers = {{.weight = 1.f}}; + layers[0].name = "50 ExplicitExactOrMultiple"; + layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; + layers[0].desiredRefreshRate = 50.00_Hz; + EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, selector.getBestScoredFrameRate(layers).frameRateMode); +} + +TEST_P(RefreshRateSelectorTest, test50Chooses60IfThresholdIs120) { + auto selector = + createSelector(kModes_60_90_120, kModeId120, {.frameRateMultipleThreshold = 120}); + std::vector<LayerRequirement> layers = {{.weight = 1.f}}; + layers[0].name = "50 ExplicitExactOrMultiple"; + layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; + layers[0].desiredRefreshRate = 50.00_Hz; + EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode); +} + +TEST_P(RefreshRateSelectorTest, test5994Chooses60) { + auto selector = createSelector(kModes_60_90_120, kModeId120); + std::vector<LayerRequirement> layers = {{.weight = 1.f}}; + layers[0].name = "59.94 ExplicitExactOrMultiple"; + layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; + layers[0].desiredRefreshRate = 59.94_Hz; + EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode); +} + TEST_P(RefreshRateSelectorTest, getFrameRateOverrides_noLayers) { auto selector = createSelector(kModes_30_60_72_90_120, kModeId120); |