diff options
116 files changed, 3290 insertions, 2168 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 83b336c62f..b99f443fa6 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -178,6 +178,7 @@ void add_mountinfo(); #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur" #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref" #define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat" +#define KERNEL_CONFIG "/proc/config.gz" #define WLUTIL "/vendor/xbin/wlutil" #define WMTRACE_DATA_DIR "/data/misc/wmtrace" #define OTA_METADATA_DIR "/metadata/ota" @@ -1951,6 +1952,8 @@ Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() { DumpFile("PSI memory", "/proc/pressure/memory"); DumpFile("PSI io", "/proc/pressure/io"); + ds.AddZipEntry(ZIP_ROOT_DIR + KERNEL_CONFIG, KERNEL_CONFIG); + RunCommand("SDK EXTENSIONS", {SDK_EXT_INFO, "--dump"}, CommandOptions::WithTimeout(10).Always().DropRoot().Build()); diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp index e54f9d3df7..870e8eb846 100644 --- a/cmds/lshal/ListCommand.cpp +++ b/cmds/lshal/ListCommand.cpp @@ -44,6 +44,7 @@ #include "Timeout.h" #include "utils.h" +using ::android::hardware::hidl_array; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hidl::base::V1_0::DebugInfo; @@ -522,27 +523,35 @@ Status ListCommand::fetchAllLibraries(const sp<IServiceManager> &manager) { using namespace ::android::hardware; using namespace ::android::hidl::manager::V1_0; using namespace ::android::hidl::base::V1_0; - using std::literals::chrono_literals::operator""s; - auto ret = timeoutIPC(10s, manager, &IServiceManager::debugDump, [&] (const auto &infos) { - std::map<std::string, TableEntry> entries; - for (const auto &info : infos) { - std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" + - std::string{info.instanceName.c_str()}; - entries.emplace(interfaceName, TableEntry{ - .interfaceName = interfaceName, - .transport = vintf::Transport::PASSTHROUGH, - .clientPids = info.clientPids, - }).first->second.arch |= fromBaseArchitecture(info.arch); - } - for (auto &&pair : entries) { - putEntry(HalType::PASSTHROUGH_LIBRARIES, std::move(pair.second)); - } - }); + + // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, + // even though the interface function call is synchronous. + // However, there's no need to lock because if ret.isOk(), the background thread has + // already ended, so it is safe to dereference entries. + auto entries = std::make_shared<std::map<std::string, TableEntry>>(); + auto ret = + timeoutIPC(mLshal.getDebugDumpWait(), manager, &IServiceManager::debugDump, + [entries](const auto& infos) { + for (const auto& info : infos) { + std::string interfaceName = std::string{info.interfaceName.c_str()} + + "/" + std::string{info.instanceName.c_str()}; + entries->emplace(interfaceName, + TableEntry{ + .interfaceName = interfaceName, + .transport = vintf::Transport::PASSTHROUGH, + .clientPids = info.clientPids, + }) + .first->second.arch |= fromBaseArchitecture(info.arch); + } + }); if (!ret.isOk()) { err() << "Error: Failed to call list on getPassthroughServiceManager(): " << ret.description() << std::endl; return DUMP_ALL_LIBS_ERROR; } + for (auto&& pair : *entries) { + putEntry(HalType::PASSTHROUGH_LIBRARIES, std::move(pair.second)); + } return OK; } @@ -553,27 +562,40 @@ Status ListCommand::fetchPassthrough(const sp<IServiceManager> &manager) { using namespace ::android::hardware::details; using namespace ::android::hidl::manager::V1_0; using namespace ::android::hidl::base::V1_0; - auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) { - for (const auto &info : infos) { - if (info.clientPids.size() <= 0) { - continue; - } - putEntry(HalType::PASSTHROUGH_CLIENTS, { - .interfaceName = - std::string{info.interfaceName.c_str()} + "/" + - std::string{info.instanceName.c_str()}, - .transport = vintf::Transport::PASSTHROUGH, - .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID, - .clientPids = info.clientPids, - .arch = fromBaseArchitecture(info.arch) - }); - } - }); + + // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, + // even though the interface function call is synchronous. + // However, there's no need to lock because if ret.isOk(), the background thread has + // already ended, so it is safe to dereference entries. + auto entries = std::make_shared<std::vector<TableEntry>>(); + auto ret = + timeoutIPC(mLshal.getIpcCallWait(), manager, &IServiceManager::debugDump, + [entries](const auto& infos) { + for (const auto& info : infos) { + if (info.clientPids.size() <= 0) { + continue; + } + entries->emplace_back( + TableEntry{.interfaceName = + std::string{info.interfaceName.c_str()} + + "/" + + std::string{info.instanceName.c_str()}, + .transport = vintf::Transport::PASSTHROUGH, + .serverPid = info.clientPids.size() == 1 + ? info.clientPids[0] + : NO_PID, + .clientPids = info.clientPids, + .arch = fromBaseArchitecture(info.arch)}); + } + }); if (!ret.isOk()) { err() << "Error: Failed to call debugDump on defaultServiceManager(): " << ret.description() << std::endl; return DUMP_PASSTHROUGH_ERROR; } + for (auto&& entry : *entries) { + putEntry(HalType::PASSTHROUGH_CLIENTS, std::move(entry)); + } return OK; } @@ -583,11 +605,14 @@ Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) { if (!shouldFetchHalType(HalType::BINDERIZED_SERVICES)) { return OK; } const vintf::Transport mode = vintf::Transport::HWBINDER; - hidl_vec<hidl_string> fqInstanceNames; - // copying out for timeoutIPC - auto listRet = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &names) { - fqInstanceNames = names; - }); + + // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, + // even though the interface function call is synchronous. + // However, there's no need to lock because if listRet.isOk(), the background thread has + // already ended, so it is safe to dereference fqInstanceNames. + auto fqInstanceNames = std::make_shared<hidl_vec<hidl_string>>(); + auto listRet = timeoutIPC(mLshal.getIpcCallWait(), manager, &IServiceManager::list, + [fqInstanceNames](const auto& names) { *fqInstanceNames = names; }); if (!listRet.isOk()) { err() << "Error: Failed to list services for " << mode << ": " << listRet.description() << std::endl; @@ -596,7 +621,7 @@ Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) { Status status = OK; std::map<std::string, TableEntry> allTableEntries; - for (const auto &fqInstanceName : fqInstanceNames) { + for (const auto& fqInstanceName : *fqInstanceNames) { // create entry and default assign all fields. TableEntry& entry = allTableEntries[fqInstanceName]; entry.interfaceName = fqInstanceName; @@ -623,7 +648,8 @@ Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager, const auto pair = splitFirst(entry->interfaceName, '/'); const auto &serviceName = pair.first; const auto &instanceName = pair.second; - auto getRet = timeoutIPC(manager, &IServiceManager::get, serviceName, instanceName); + auto getRet = timeoutIPC(mLshal.getIpcCallWait(), manager, &IServiceManager::get, serviceName, + instanceName); if (!getRet.isOk()) { handleError(TRANSACTION_ERROR, "cannot be fetched from service manager:" + getRet.description()); @@ -637,30 +663,33 @@ Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager, // getDebugInfo do { - DebugInfo debugInfo; - auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &received) { - debugInfo = received; - }); + // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, + // even though the interface function call is synchronous. + // However, there's no need to lock because if debugRet.isOk(), the background thread has + // already ended, so it is safe to dereference debugInfo. + auto debugInfo = std::make_shared<DebugInfo>(); + auto debugRet = timeoutIPC(mLshal.getIpcCallWait(), service, &IBase::getDebugInfo, + [debugInfo](const auto& received) { *debugInfo = received; }); if (!debugRet.isOk()) { handleError(TRANSACTION_ERROR, "debugging information cannot be retrieved: " + debugRet.description()); break; // skip getPidInfo } - entry->serverPid = debugInfo.pid; - entry->serverObjectAddress = debugInfo.ptr; - entry->arch = fromBaseArchitecture(debugInfo.arch); + entry->serverPid = debugInfo->pid; + entry->serverObjectAddress = debugInfo->ptr; + entry->arch = fromBaseArchitecture(debugInfo->arch); - if (debugInfo.pid != NO_PID) { - const BinderPidInfo* pidInfo = getPidInfoCached(debugInfo.pid); + if (debugInfo->pid != NO_PID) { + const BinderPidInfo* pidInfo = getPidInfoCached(debugInfo->pid); if (pidInfo == nullptr) { handleError(IO_ERROR, - "no information for PID " + std::to_string(debugInfo.pid) + - ", are you root?"); + "no information for PID " + std::to_string(debugInfo->pid) + + ", are you root?"); break; } - if (debugInfo.ptr != NO_PTR) { - auto it = pidInfo->refPids.find(debugInfo.ptr); + if (debugInfo->ptr != NO_PTR) { + auto it = pidInfo->refPids.find(debugInfo->ptr); if (it != pidInfo->refPids.end()) { entry->clientPids = it->second; } @@ -672,39 +701,46 @@ Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager, // hash do { - ssize_t hashIndex = -1; - auto ifaceChainRet = timeoutIPC(service, &IBase::interfaceChain, [&] (const auto& c) { - for (size_t i = 0; i < c.size(); ++i) { - if (serviceName == c[i]) { - hashIndex = static_cast<ssize_t>(i); - break; - } - } - }); + // The lambda function may be executed asynchrounously because it is passed to timeoutIPC, + // even though the interface function call is synchronous. + auto hashIndexStore = std::make_shared<ssize_t>(-1); + auto ifaceChainRet = timeoutIPC(mLshal.getIpcCallWait(), service, &IBase::interfaceChain, + [hashIndexStore, serviceName](const auto& c) { + for (size_t i = 0; i < c.size(); ++i) { + if (serviceName == c[i]) { + *hashIndexStore = static_cast<ssize_t>(i); + break; + } + } + }); if (!ifaceChainRet.isOk()) { handleError(TRANSACTION_ERROR, "interfaceChain fails: " + ifaceChainRet.description()); break; // skip getHashChain } + // if ifaceChainRet.isOk(), the background thread has already ended, so it is safe to + // dereference hashIndex without any locking. + auto hashIndex = *hashIndexStore; if (hashIndex < 0) { handleError(BAD_IMPL, "Interface name does not exist in interfaceChain."); break; // skip getHashChain } - auto hashRet = timeoutIPC(service, &IBase::getHashChain, [&] (const auto& hashChain) { - if (static_cast<size_t>(hashIndex) >= hashChain.size()) { - handleError(BAD_IMPL, - "interfaceChain indicates position " + std::to_string(hashIndex) + - " but getHashChain returns " + std::to_string(hashChain.size()) + - " hashes"); - return; - } - - auto&& hashArray = hashChain[hashIndex]; - entry->hash = android::base::HexString(hashArray.data(), hashArray.size()); - }); + // See comments about hashIndex above. + auto hashChain = std::make_shared<hidl_vec<hidl_array<uint8_t, 32>>>(); + auto hashRet = timeoutIPC(mLshal.getIpcCallWait(), service, &IBase::getHashChain, + [hashChain](const auto& ret) { *hashChain = std::move(ret); }); if (!hashRet.isOk()) { handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description()); } + if (static_cast<size_t>(hashIndex) >= hashChain->size()) { + handleError(BAD_IMPL, + "interfaceChain indicates position " + std::to_string(hashIndex) + + " but getHashChain returns " + std::to_string(hashChain->size()) + + " hashes"); + } else { + auto&& hashArray = (*hashChain)[hashIndex]; + entry->hash = android::base::HexString(hashArray.data(), hashArray.size()); + } } while (0); if (status == OK) { entry->serviceStatus = ServiceStatus::ALIVE; diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp index a5f98c2a9e..6115da75b2 100644 --- a/cmds/lshal/Lshal.cpp +++ b/cmds/lshal/Lshal.cpp @@ -250,5 +250,17 @@ const sp<IServiceManager> &Lshal::passthroughManager() const { return mPassthroughManager; } +void Lshal::setWaitTimeForTest(std::chrono::milliseconds ipcCallWait, + std::chrono::milliseconds debugDumpWait) { + mIpcCallWait = ipcCallWait; + mDebugDumpWait = debugDumpWait; +} +std::chrono::milliseconds Lshal::getIpcCallWait() const { + return mIpcCallWait; +} +std::chrono::milliseconds Lshal::getDebugDumpWait() const { + return mDebugDumpWait; +} + } // namespace lshal } // namespace android diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h index 50279d4d7a..cb2820c535 100644 --- a/cmds/lshal/Lshal.h +++ b/cmds/lshal/Lshal.h @@ -16,6 +16,7 @@ #pragma once +#include <chrono> #include <iostream> #include <string> @@ -58,6 +59,11 @@ public: void forEachCommand(const std::function<void(const Command* c)>& f) const; + void setWaitTimeForTest(std::chrono::milliseconds ipcCallWait, + std::chrono::milliseconds debugDumpWait); + std::chrono::milliseconds getIpcCallWait() const; + std::chrono::milliseconds getDebugDumpWait() const; + private: Status parseArgs(const Arg &arg); @@ -70,6 +76,9 @@ private: std::vector<std::unique_ptr<Command>> mRegisteredCommands; + std::chrono::milliseconds mIpcCallWait{500}; + std::chrono::milliseconds mDebugDumpWait{10000}; + DISALLOW_COPY_AND_ASSIGN(Lshal); }; diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h index e8d22d9b58..805e8dc43a 100644 --- a/cmds/lshal/Timeout.h +++ b/cmds/lshal/Timeout.h @@ -27,8 +27,6 @@ namespace android { namespace lshal { -static constexpr std::chrono::milliseconds IPC_CALL_WAIT{500}; - class BackgroundTaskState { public: explicit BackgroundTaskState(std::function<void(void)> &&func) @@ -96,12 +94,5 @@ timeoutIPC(std::chrono::duration<R, P> wait, const sp<I> &interfaceObject, Funct return ret; } -template<class Function, class I, class... Args> -typename std::result_of<Function(I *, Args...)>::type -timeoutIPC(const sp<I> &interfaceObject, Function &&func, Args &&... args) { - return timeoutIPC(IPC_CALL_WAIT, interfaceObject, func, args...); -} - - } // namespace lshal } // namespace android diff --git a/include/input/Input.h b/include/input/Input.h index 1c4ea6b416..7b253a53ef 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -515,6 +515,8 @@ struct PointerProperties { PointerProperties& operator=(const PointerProperties&) = default; }; +std::ostream& operator<<(std::ostream& out, const PointerProperties& properties); + // TODO(b/211379801) : Use a strong type from ftl/mixins.h instead using DeviceId = int32_t; diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h index 83fffa37c6..3470be4dce 100644 --- a/include/input/PrintTools.h +++ b/include/input/PrintTools.h @@ -117,11 +117,12 @@ std::string dumpMapKeys(const std::map<K, V>& map, template <typename T> std::string dumpVector(const std::vector<T>& values, std::string (*valueToString)(const T&) = constToString) { - std::string dump = valueToString(values[0]); - for (size_t i = 1; i < values.size(); i++) { - dump += ", " + valueToString(values[i]); + std::string out; + for (const auto& value : values) { + out += out.empty() ? "[" : ", "; + out += valueToString(value); } - return dump; + return out.empty() ? "[]" : (out + "]"); } const char* toString(bool value); diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index bf3699ccab..ae0fb018ef 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -258,7 +258,9 @@ cc_defaults { "-DBINDER_DISABLE_NATIVE_HANDLE", "-DBINDER_DISABLE_BLOB", "-DBINDER_NO_LIBBASE", + // TODO: switch to "vendor: true" rather than copying this // Trusty libbinder uses vendor stability for its binders + "-D__ANDROID_VENDOR__", "-D__ANDROID_VNDK__", "-U__ANDROID__", "-D__TRUSTY__", diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 9341eff91e..b92e504a9a 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -67,28 +67,28 @@ namespace android { // Static const and functions will be optimized out if not used, // when LOG_NDEBUG and references in IF_LOG_COMMANDS() are optimized out. -static const char *kReturnStrings[] = { - "BR_ERROR", - "BR_OK", - "BR_TRANSACTION", - "BR_REPLY", - "BR_ACQUIRE_RESULT", - "BR_DEAD_REPLY", - "BR_TRANSACTION_COMPLETE", - "BR_INCREFS", - "BR_ACQUIRE", - "BR_RELEASE", - "BR_DECREFS", - "BR_ATTEMPT_ACQUIRE", - "BR_NOOP", - "BR_SPAWN_LOOPER", - "BR_FINISHED", - "BR_DEAD_BINDER", - "BR_CLEAR_DEATH_NOTIFICATION_DONE", - "BR_FAILED_REPLY", - "BR_FROZEN_REPLY", - "BR_ONEWAY_SPAM_SUSPECT", - "BR_TRANSACTION_SEC_CTX", +static const char* kReturnStrings[] = { + "BR_ERROR", + "BR_OK", + "BR_TRANSACTION/BR_TRANSACTION_SEC_CTX", + "BR_REPLY", + "BR_ACQUIRE_RESULT", + "BR_DEAD_REPLY", + "BR_TRANSACTION_COMPLETE", + "BR_INCREFS", + "BR_ACQUIRE", + "BR_RELEASE", + "BR_DECREFS", + "BR_ATTEMPT_ACQUIRE", + "BR_NOOP", + "BR_SPAWN_LOOPER", + "BR_FINISHED", + "BR_DEAD_BINDER", + "BR_CLEAR_DEATH_NOTIFICATION_DONE", + "BR_FAILED_REPLY", + "BR_FROZEN_REPLY", + "BR_ONEWAY_SPAM_SUSPECT", + "BR_TRANSACTION_PENDING_FROZEN", }; static const char *kCommandStrings[] = { diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp index c432b3af29..665dfea456 100644 --- a/libs/binder/Stability.cpp +++ b/libs/binder/Stability.cpp @@ -73,6 +73,14 @@ void Stability::tryMarkCompilationUnit(IBinder* binder) { (void)setRepr(binder, getLocalLevel(), REPR_NONE); } +// after deprecation of the VNDK, these should be aliases. At some point +// all references to __ANDROID_VNDK__ should be replaced by __ANDROID_VENDOR__ +// but for right now, check that this condition holds because some +// places check __ANDROID_VNDK__ and some places check __ANDROID_VENDOR__ +#if defined(__ANDROID_VNDK__) != defined(__ANDROID_VENDOR__) +#error "__ANDROID_VNDK__ and __ANDROID_VENDOR__ should be aliases" +#endif + Stability::Level Stability::getLocalLevel() { #ifdef __ANDROID_APEX__ #error "APEX can't use libbinder (must use libbinder_ndk)" diff --git a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h index f178027b35..8d2944afd8 100644 --- a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h +++ b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h @@ -31,7 +31,11 @@ namespace aidl::android::os { */ class PersistableBundle { public: - PersistableBundle() noexcept : mPBundle(APersistableBundle_new()) {} + PersistableBundle() noexcept { + if (__builtin_available(android __ANDROID_API_V__, *)) { + mPBundle = APersistableBundle_new(); + } + } // takes ownership of the APersistableBundle* PersistableBundle(APersistableBundle* _Nonnull bundle) noexcept : mPBundle(bundle) {} // takes ownership of the APersistableBundle* @@ -327,20 +331,32 @@ class PersistableBundle { } bool getBooleanVector(const std::string& key, std::vector<bool>* _Nonnull vec) { - return getVecInternal<bool>(&APersistableBundle_getBooleanVector, mPBundle, key.c_str(), - vec); + if (__builtin_available(android __ANDROID_API_V__, *)) { + return getVecInternal<bool>(&APersistableBundle_getBooleanVector, mPBundle, key.c_str(), + vec); + } + return false; } bool getIntVector(const std::string& key, std::vector<int32_t>* _Nonnull vec) { - return getVecInternal<int32_t>(&APersistableBundle_getIntVector, mPBundle, key.c_str(), + if (__builtin_available(android __ANDROID_API_V__, *)) { + return getVecInternal<int32_t>(&APersistableBundle_getIntVector, mPBundle, key.c_str(), vec); + } + return false; } bool getLongVector(const std::string& key, std::vector<int64_t>* _Nonnull vec) { - return getVecInternal<int64_t>(&APersistableBundle_getLongVector, mPBundle, key.c_str(), + if (__builtin_available(android __ANDROID_API_V__, *)) { + return getVecInternal<int64_t>(&APersistableBundle_getLongVector, mPBundle, key.c_str(), vec); + } + return false; } bool getDoubleVector(const std::string& key, std::vector<double>* _Nonnull vec) { - return getVecInternal<double>(&APersistableBundle_getDoubleVector, mPBundle, key.c_str(), + if (__builtin_available(android __ANDROID_API_V__, *)) { + return getVecInternal<double>(&APersistableBundle_getDoubleVector, mPBundle, key.c_str(), vec); + } + return false; } // Takes ownership of and frees the char** and its elements. @@ -361,15 +377,17 @@ class PersistableBundle { } bool getStringVector(const std::string& key, std::vector<std::string>* _Nonnull vec) { - int32_t bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), nullptr, 0, - &stringAllocator, nullptr); - if (bytes > 0) { - char** strings = (char**)malloc(bytes); - if (strings) { - bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), strings, bytes, - &stringAllocator, nullptr); - *vec = moveStringsInternal<std::vector<std::string>>(strings, bytes); - return true; + if (__builtin_available(android __ANDROID_API_V__, *)) { + int32_t bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), nullptr, 0, + &stringAllocator, nullptr); + if (bytes > 0) { + char** strings = (char**)malloc(bytes); + if (strings) { + bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), strings, bytes, + &stringAllocator, nullptr); + *vec = moveStringsInternal<std::vector<std::string>>(strings, bytes); + return true; + } } } return false; diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index e4d4de86bc..dd2be94a76 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -256,6 +256,12 @@ cc_defaults { // contention on the device. b/276820894 test_options: { unit_test: false, + test_runner_options: [ + { + name: "native-test-timeout", + value: "10m", + }, + ], }, test_suites: ["general-tests"], @@ -830,6 +836,7 @@ cc_defaults { ], // Adds bugs to hotlist "AIDL fuzzers bugs" on buganizer hotlists: ["4637097"], + use_for_presubmit: true, }, } diff --git a/libs/binder/trusty/kernel/rules.mk b/libs/binder/trusty/kernel/rules.mk index 788184d2ce..5cbe0afafa 100644 --- a/libs/binder/trusty/kernel/rules.mk +++ b/libs/binder/trusty/kernel/rules.mk @@ -69,6 +69,7 @@ GLOBAL_COMPILEFLAGS += \ -DBINDER_DISABLE_NATIVE_HANDLE \ -DBINDER_DISABLE_BLOB \ -DBINDER_NO_LIBBASE \ + -D__ANDROID_VENDOR__ \ -D__ANDROID_VNDK__ \ MODULE_DEPS += \ diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk index e0f821f2c9..f2f140d9ba 100644 --- a/libs/binder/trusty/rules.mk +++ b/libs/binder/trusty/rules.mk @@ -72,6 +72,7 @@ MODULE_EXPORT_COMPILEFLAGS += \ -DBINDER_DISABLE_NATIVE_HANDLE \ -DBINDER_DISABLE_BLOB \ -DBINDER_NO_LIBBASE \ + -D__ANDROID_VENDOR__ \ -D__ANDROID_VNDK__ \ # libbinder has some deprecated declarations that we want to produce warnings diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 44a9e52d5b..eb4d3df21d 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -423,7 +423,6 @@ cc_defaults { "libhidlbase", "liblog", "libnativewindow", - "libselinux", "libsync", "libui", "libutils", diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 744201a5df..11f5174d76 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -38,43 +38,10 @@ #include <private/gui/BufferQueueThreadState.h> #if !defined(__ANDROID_VNDK__) && !defined(NO_BINDER) #include <binder/PermissionCache.h> -#include <selinux/android.h> -#include <selinux/selinux.h> #endif #include <system/window.h> -namespace { -#if !defined(__ANDROID_VNDK__) && !defined(NO_BINDER) -int selinux_log_suppress_callback(int, const char*, ...) { // NOLINT - // DO NOTHING - return 0; -} - -bool hasAccessToPermissionService() { - char* ctx; - - if (getcon(&ctx) == -1) { - // Failed to get current selinux context - return false; - } - - union selinux_callback cb; - - cb.func_log = selinux_log_suppress_callback; - selinux_set_callback(SELINUX_CB_LOG, cb); - - bool hasAccess = selinux_check_access(ctx, "u:object_r:permission_service:s0", - "service_manager", "find", NULL) == 0; - freecon(ctx); - cb.func_log = hasAccess ? selinux_log_callback : selinux_vendor_log_callback; - selinux_set_callback(SELINUX_CB_LOG, cb); - - return hasAccess; -} -#endif -} // namespace - namespace android { // Macros for include BufferQueueCore information in log messages @@ -843,18 +810,14 @@ status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResul const uid_t uid = BufferQueueThreadState::getCallingUid(); #if !defined(__ANDROID_VNDK__) && !defined(NO_BINDER) // permission check can't be done for vendors as vendors have no access to - // the PermissionController. We need to do a runtime check as well, since - // the system variant of libgui can be loaded in a vendor process. For eg: - // if a HAL uses an llndk library that depends on libgui (libmediandk etc). - if (hasAccessToPermissionService()) { - const pid_t pid = BufferQueueThreadState::getCallingPid(); - if ((uid != shellUid) && - !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) { - outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer " - "from pid=%d, uid=%d\n", - pid, uid); - denied = true; - } + // the PermissionController. + const pid_t pid = BufferQueueThreadState::getCallingPid(); + if ((uid != shellUid) && + !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) { + outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer " + "from pid=%d, uid=%d\n", + pid, uid); + denied = true; } #else if (uid != shellUid) { diff --git a/libs/gui/Choreographer.cpp b/libs/gui/Choreographer.cpp index 93df12471d..c6f33639c7 100644 --- a/libs/gui/Choreographer.cpp +++ b/libs/gui/Choreographer.cpp @@ -344,6 +344,10 @@ void Choreographer::dispatchNullEvent(nsecs_t, PhysicalDisplayId) { handleRefreshRateUpdates(); } +void Choreographer::dispatchHdcpLevelsChanged(PhysicalDisplayId, int32_t, int32_t) { + LOG_ALWAYS_FATAL("dispatchHdcpLevelsChanged was called but was never registered"); +} + void Choreographer::handleMessage(const Message& message) { switch (message.what) { case MSG_SCHEDULE_CALLBACKS: diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index 5dd058cf9f..f3de96d2cd 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -195,6 +195,11 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, dispatchFrameRateOverrides(ev.header.timestamp, ev.header.displayId, std::move(mFrameRateOverrides)); break; + case DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE: + dispatchHdcpLevelsChanged(ev.header.displayId, + ev.hdcpLevelsChange.connectedLevel, + ev.hdcpLevelsChange.maxLevel); + break; default: ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type); break; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 8b6f2023dc..8d18551b69 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -3117,7 +3117,6 @@ status_t SurfaceComposerClient::removeWindowInfosListener( ->removeWindowInfosListener(windowInfosListener, ComposerServiceAIDL::getComposerService()); } - // ---------------------------------------------------------------------------- status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs, diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index 9933680c4b..c952ba2e10 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -207,6 +207,7 @@ public: MOCK_METHOD2(dispatchNullEvent, void(nsecs_t, PhysicalDisplayId)); MOCK_METHOD3(dispatchFrameRateOverrides, void(nsecs_t, PhysicalDisplayId, std::vector<FrameRateOverride>)); + MOCK_METHOD3(dispatchHdcpLevelsChanged, void(PhysicalDisplayId, int32_t, int32_t)); }; } // namespace android diff --git a/libs/gui/include/gui/Choreographer.h b/libs/gui/include/gui/Choreographer.h index 9fef512b64..55a7aa7ddc 100644 --- a/libs/gui/include/gui/Choreographer.h +++ b/libs/gui/include/gui/Choreographer.h @@ -116,6 +116,8 @@ private: void dispatchNullEvent(nsecs_t, PhysicalDisplayId) override; void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) override; + void dispatchHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel, + int32_t maxLevel) override; void scheduleCallbacks(); diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index fe2dd206ed..82cd50c7bd 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -65,6 +65,9 @@ private: virtual void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) = 0; + virtual void dispatchHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel, + int32_t maxLevel) = 0; + bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount, VsyncEventData* outVsyncEventData); diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 79582ce685..8c1103bfc2 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -58,7 +58,6 @@ static inline constexpr uint32_t fourcc(char c1, char c2, char c3, char c4) { // ---------------------------------------------------------------------------- class DisplayEventReceiver { public: - enum { DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'), DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'), @@ -66,6 +65,7 @@ public: DISPLAY_EVENT_NULL = fourcc('n', 'u', 'l', 'l'), DISPLAY_EVENT_FRAME_RATE_OVERRIDE = fourcc('r', 'a', 't', 'e'), DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH = fourcc('f', 'l', 's', 'h'), + DISPLAY_EVENT_HDCP_LEVELS_CHANGE = fourcc('h', 'd', 'c', 'p'), }; struct Event { @@ -101,12 +101,22 @@ public: float frameRateHz __attribute__((aligned(8))); }; + /* + * The values are defined in aidl: + * hardware/interfaces/drm/aidl/android/hardware/drm/HdcpLevel.aidl + */ + struct HdcpLevelsChange { + int32_t connectedLevel; + int32_t maxLevel; + }; + Header header; union { VSync vsync; Hotplug hotplug; ModeChange modeChange; FrameRateOverride frameRateOverride; + HdcpLevelsChange hdcpLevelsChange; }; }; diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 4d4c5e4394..b72b71a3ce 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -176,6 +176,8 @@ struct WindowInfo : public Parcelable { static_cast<uint32_t>(os::InputConfig::INTERCEPTS_STYLUS), CLONE = static_cast<uint32_t>(os::InputConfig::CLONE), + GLOBAL_STYLUS_BLOCKS_TOUCH = + static_cast<uint32_t>(os::InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH), // clang-format on }; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index bd5b67b1d0..8eaff00cbd 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -379,6 +379,11 @@ std::ostream& operator<<(std::ostream& out, const KeyEvent& event) { return out; } +std::ostream& operator<<(std::ostream& out, const PointerProperties& properties) { + out << "Pointer(id=" << properties.id << ", " << ftl::enum_string(properties.toolType) << ")"; + return out; +} + // --- PointerCoords --- float PointerCoords::getAxisValue(int32_t axis) const { diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 09e98d0515..669f801764 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -646,7 +646,7 @@ status_t InputPublisher::publishMotionEvent( "action=%s, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, " "metaState=0x%x, buttonState=0x%x, classification=%s," "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", " - "pointerCount=%" PRIu32 " \n%s", + "pointerCount=%" PRIu32 "\n%s", mChannel->getName().c_str(), __func__, seq, eventId, deviceId, inputEventSourceToString(source).c_str(), displayId, MotionEvent::actionToString(action).c_str(), actionButton, flags, edgeFlags, diff --git a/libs/input/android/os/InputConfig.aidl b/libs/input/android/os/InputConfig.aidl index 4e644fff06..5d391551c2 100644 --- a/libs/input/android/os/InputConfig.aidl +++ b/libs/input/android/os/InputConfig.aidl @@ -150,4 +150,11 @@ enum InputConfig { * likely a duplicate window with the same client token, but different bounds. */ CLONE = 1 << 16, + + /** + * If the stylus is currently down *anywhere* on the screen, new touches will not be delivered + * to the window with this flag. This helps prevent unexpected clicks on some system windows, + * like StatusBar and TaskBar. + */ + GLOBAL_STYLUS_BLOCKS_TOUCH = 1 << 17, } diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index 54eeb39935..11f69941bd 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -52,7 +52,14 @@ flag { flag { name: "enable_touchpad_typing_palm_rejection" namespace: "input" - description: "Enable additional palm rejection on touchpad while typing" + description: "Enabling additional touchpad palm rejection will disable the tap to click while the user is typing on a physical keyboard" + bug: "301055381" +} + +flag { + name: "enable_v2_touchpad_typing_palm_rejection" + namespace: "input" + description: "In addition to touchpad palm rejection v1, v2 will also cancel ongoing move gestures while typing and add delay in re-enabling the tap to click." bug: "301055381" } diff --git a/libs/nativewindow/include/android/native_window_aidl.h b/libs/nativewindow/include/android/native_window_aidl.h index 0d5727d0e6..68ac7e0b34 100644 --- a/libs/nativewindow/include/android/native_window_aidl.h +++ b/libs/nativewindow/include/android/native_window_aidl.h @@ -103,14 +103,22 @@ public: binder_status_t readFromParcel(const AParcel* _Nonnull parcel) { reset(); - return ANativeWindow_readFromParcel(parcel, &mWindow); + if (__builtin_available(android __ANDROID_API_U__, *)) { + return ANativeWindow_readFromParcel(parcel, &mWindow); + } else { + return STATUS_FAILED_TRANSACTION; + } } binder_status_t writeToParcel(AParcel* _Nonnull parcel) const { if (!mWindow) { return STATUS_BAD_VALUE; } - return ANativeWindow_writeToParcel(mWindow, parcel); + if (__builtin_available(android __ANDROID_API_U__, *)) { + return ANativeWindow_writeToParcel(mWindow, parcel); + } else { + return STATUS_FAILED_TRANSACTION; + } } /** diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp index d112a1265c..f8ee3fc607 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -248,6 +248,22 @@ ssize_t SensorManager::getSensorList(Sensor const* const** list) { return static_cast<ssize_t>(mSensors.size()); } +ssize_t SensorManager::getDefaultDeviceSensorList(Vector<Sensor> & list) { + Mutex::Autolock _l(mLock); + status_t err = assertStateLocked(); + if (err < 0) { + return static_cast<ssize_t>(err); + } + + if (mDeviceId == DEVICE_ID_DEFAULT) { + list = mSensors; + } else { + list = mSensorServer->getSensorList(mOpPackageName); + } + + return static_cast<ssize_t>(list.size()); +} + ssize_t SensorManager::getDynamicSensorList(Vector<Sensor> & dynamicSensors) { Mutex::Autolock _l(mLock); status_t err = assertStateLocked(); diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h index e67fac7617..49f050a0ac 100644 --- a/libs/sensor/include/sensor/SensorManager.h +++ b/libs/sensor/include/sensor/SensorManager.h @@ -58,6 +58,7 @@ public: ~SensorManager(); ssize_t getSensorList(Sensor const* const** list); + ssize_t getDefaultDeviceSensorList(Vector<Sensor> & list); ssize_t getDynamicSensorList(Vector<Sensor>& list); ssize_t getDynamicSensorList(Sensor const* const** list); ssize_t getRuntimeSensorList(int deviceId, Vector<Sensor>& list); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 6033398b25..112f16b38a 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -72,7 +72,8 @@ using android::os::InputEventInjectionResult; using android::os::InputEventInjectionSync; namespace input_flags = com::android::input::flags; -static const bool REMOVE_APP_SWITCH_DROPS = input_flags::remove_app_switch_drops(); +// TODO(b/312714754): remove the corresponding code, as well. +static const bool REMOVE_APP_SWITCH_DROPS = true; namespace android::inputdispatcher { @@ -252,6 +253,14 @@ Result<void> validateInputEvent(const InputEvent& event) { } } +std::bitset<MAX_POINTER_ID + 1> getPointerIds(const std::vector<PointerProperties>& pointers) { + std::bitset<MAX_POINTER_ID + 1> pointerIds; + for (const PointerProperties& pointer : pointers) { + pointerIds.set(pointer.id); + } + return pointerIds; +} + std::string dumpRegion(const Region& region) { if (region.isEmpty()) { return "<empty>"; @@ -630,15 +639,15 @@ std::vector<TouchedWindow> getHoveringWindowsLocked(const TouchState* oldState, } // We should consider all hovering pointers here. But for now, just use the first one - const int32_t pointerId = entry.pointerProperties[0].id; + const PointerProperties& pointer = entry.pointerProperties[0]; std::set<sp<WindowInfoHandle>> oldWindows; if (oldState != nullptr) { - oldWindows = oldState->getWindowsWithHoveringPointer(entry.deviceId, pointerId); + oldWindows = oldState->getWindowsWithHoveringPointer(entry.deviceId, pointer.id); } std::set<sp<WindowInfoHandle>> newWindows = - newTouchState.getWindowsWithHoveringPointer(entry.deviceId, pointerId); + newTouchState.getWindowsWithHoveringPointer(entry.deviceId, pointer.id); // If the pointer is no longer in the new window set, send HOVER_EXIT. for (const sp<WindowInfoHandle>& oldWindow : oldWindows) { @@ -672,7 +681,7 @@ std::vector<TouchedWindow> getHoveringWindowsLocked(const TouchState* oldState, } touchedWindow.dispatchMode = InputTarget::DispatchMode::AS_IS; } - touchedWindow.addHoveringPointer(entry.deviceId, pointerId); + touchedWindow.addHoveringPointer(entry.deviceId, pointer); if (canReceiveForegroundTouches(*newWindow->getInfo())) { touchedWindow.targetFlags |= InputTarget::Flags::FOREGROUND; } @@ -740,6 +749,20 @@ bool shouldSplitTouch(const TouchState& touchState, const MotionEntry& entry) { return true; } +/** + * Return true if stylus is currently down anywhere on the specified display, and false otherwise. + */ +bool isStylusActiveInDisplay( + int32_t displayId, + const std::unordered_map<int32_t /*displayId*/, TouchState>& touchStatesByDisplay) { + const auto it = touchStatesByDisplay.find(displayId); + if (it == touchStatesByDisplay.end()) { + return false; + } + const TouchState& state = it->second; + return state.hasActiveStylus(); +} + } // namespace // --- InputDispatcher --- @@ -2135,7 +2158,6 @@ bool InputDispatcher::shouldWaitToSendKeyLocked(nsecs_t currentTime, sp<WindowInfoHandle> InputDispatcher::findFocusedWindowTargetLocked( nsecs_t currentTime, const EventEntry& entry, nsecs_t* nextWakeupTime, InputEventInjectionResult& outInjectionResult) { - std::string reason; outInjectionResult = InputEventInjectionResult::FAILED; // Default result int32_t displayId = getTargetDisplayId(entry); @@ -2320,7 +2342,7 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ const auto [x, y] = resolveTouchedPosition(entry); const int32_t pointerIndex = MotionEvent::getActionIndex(action); - const int32_t pointerId = entry.pointerProperties[pointerIndex].id; + const PointerProperties& pointer = entry.pointerProperties[pointerIndex]; // Outside targets should be added upon first dispatched DOWN event. That means, this should // be a pointer that would generate ACTION_DOWN, *and* touch should not already be down. const bool isStylus = isPointerFromStylus(entry, pointerIndex); @@ -2328,7 +2350,7 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( findTouchedWindowAtLocked(displayId, x, y, isStylus); if (isDown) { - targets += findOutsideTargetsLocked(displayId, newTouchedWindowHandle, pointerId); + targets += findOutsideTargetsLocked(displayId, newTouchedWindowHandle, pointer.id); } // Handle the case where we did not find a window. if (newTouchedWindowHandle == nullptr) { @@ -2386,7 +2408,7 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( if (isHoverAction) { // The "windowHandle" is the target of this hovering pointer. - tempTouchState.addHoveringPointerToWindow(windowHandle, entry.deviceId, pointerId); + tempTouchState.addHoveringPointerToWindow(windowHandle, entry.deviceId, pointer); } // Set target flags. @@ -2409,12 +2431,10 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( // Update the temporary touch state. if (!isHoverAction) { - std::bitset<MAX_POINTER_ID + 1> pointerIds; - pointerIds.set(pointerId); const bool isDownOrPointerDown = maskedAction == AMOTION_EVENT_ACTION_DOWN || maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN; tempTouchState.addOrUpdateWindow(windowHandle, InputTarget::DispatchMode::AS_IS, - targetFlags, entry.deviceId, pointerIds, + targetFlags, entry.deviceId, {pointer}, isDownOrPointerDown ? std::make_optional(entry.eventTime) : std::nullopt); @@ -2437,7 +2457,7 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( } tempTouchState.addOrUpdateWindow(wallpaper, InputTarget::DispatchMode::AS_IS, - wallpaperFlags, entry.deviceId, pointerIds, + wallpaperFlags, entry.deviceId, {pointer}, entry.eventTime); } } @@ -2448,12 +2468,12 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( // make it pilfering. This will prevent other non-spy windows from getting this pointer, // which is a specific behaviour that we want. for (TouchedWindow& touchedWindow : tempTouchState.windows) { - if (touchedWindow.hasTouchingPointer(entry.deviceId, pointerId) && + if (touchedWindow.hasTouchingPointer(entry.deviceId, pointer.id) && touchedWindow.hasPilferingPointers(entry.deviceId)) { // This window is already pilfering some pointers, and this new pointer is also // going to it. Therefore, take over this pointer and don't give it to anyone // else. - touchedWindow.addPilferingPointer(entry.deviceId, pointerId); + touchedWindow.addPilferingPointer(entry.deviceId, pointer.id); } } @@ -2522,8 +2542,8 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( // Make a slippery exit from the old window. std::bitset<MAX_POINTER_ID + 1> pointerIds; - const int32_t pointerId = entry.pointerProperties[0].id; - pointerIds.set(pointerId); + const PointerProperties& pointer = entry.pointerProperties[0]; + pointerIds.set(pointer.id); const TouchedWindow& touchedWindow = tempTouchState.getTouchedWindow(oldTouchedWindowHandle); @@ -2553,13 +2573,13 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, InputTarget::DispatchMode::SLIPPERY_ENTER, - targetFlags, entry.deviceId, pointerIds, + targetFlags, entry.deviceId, {pointer}, entry.eventTime); // Check if the wallpaper window should deliver the corresponding event. slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle, - tempTouchState, entry.deviceId, pointerId, targets); - tempTouchState.removeTouchingPointerFromWindow(entry.deviceId, pointerId, + tempTouchState, entry.deviceId, pointer, targets); + tempTouchState.removeTouchingPointerFromWindow(entry.deviceId, pointer.id, oldTouchedWindowHandle); } } @@ -2568,14 +2588,12 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) { // If no split, we suppose all touched windows should receive pointer down. const int32_t pointerIndex = MotionEvent::getActionIndex(action); - for (size_t i = 0; i < tempTouchState.windows.size(); i++) { - TouchedWindow& touchedWindow = tempTouchState.windows[i]; + std::vector<PointerProperties> touchingPointers{entry.pointerProperties[pointerIndex]}; + for (TouchedWindow& touchedWindow : tempTouchState.windows) { // Ignore drag window for it should just track one pointer. if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) { continue; } - std::bitset<MAX_POINTER_ID + 1> touchingPointers; - touchingPointers.set(entry.pointerProperties[pointerIndex].id); touchedWindow.addTouchingPointers(entry.deviceId, touchingPointers); } } @@ -2646,13 +2664,13 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( // Output targets from the touch state. for (const TouchedWindow& touchedWindow : tempTouchState.windows) { - std::bitset<MAX_POINTER_ID + 1> touchingPointers = + std::vector<PointerProperties> touchingPointers = touchedWindow.getTouchingPointers(entry.deviceId); - if (touchingPointers.none()) { + if (touchingPointers.empty()) { continue; } addPointerWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.dispatchMode, - touchedWindow.targetFlags, touchingPointers, + touchedWindow.targetFlags, getPointerIds(touchingPointers), touchedWindow.getDownTimeInTarget(entry.deviceId), targets); } @@ -3371,27 +3389,40 @@ void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connectio dispatchEntry->resolvedFlags = resolvedFlags; if (resolvedAction != motionEntry.action) { + std::optional<std::vector<PointerProperties>> usingProperties; + std::optional<std::vector<PointerCoords>> usingCoords; + if (resolvedAction == AMOTION_EVENT_ACTION_HOVER_EXIT || + resolvedAction == AMOTION_EVENT_ACTION_CANCEL) { + // This is a HOVER_EXIT or an ACTION_CANCEL event that was synthesized by + // the dispatcher, and therefore the coordinates of this event are currently + // incorrect. These events should use the coordinates of the last dispatched + // ACTION_MOVE or HOVER_MOVE. We need to query InputState to get this data. + const bool hovering = resolvedAction == AMOTION_EVENT_ACTION_HOVER_EXIT; + std::optional<std::pair<std::vector<PointerProperties>, + std::vector<PointerCoords>>> + pointerInfo = + connection->inputState.getPointersOfLastEvent(motionEntry, + hovering); + if (pointerInfo) { + usingProperties = pointerInfo->first; + usingCoords = pointerInfo->second; + } + } // Generate a new MotionEntry with a new eventId using the resolved action and // flags. - resolvedMotion = - std::make_shared<MotionEntry>(mIdGenerator.nextId(), - motionEntry.injectionState, - motionEntry.eventTime, - motionEntry.deviceId, motionEntry.source, - motionEntry.displayId, - motionEntry.policyFlags, resolvedAction, - motionEntry.actionButton, resolvedFlags, - motionEntry.metaState, - motionEntry.buttonState, - motionEntry.classification, - motionEntry.edgeFlags, - motionEntry.xPrecision, - motionEntry.yPrecision, - motionEntry.xCursorPosition, - motionEntry.yCursorPosition, - motionEntry.downTime, - motionEntry.pointerProperties, - motionEntry.pointerCoords); + resolvedMotion = std::make_shared< + MotionEntry>(mIdGenerator.nextId(), motionEntry.injectionState, + motionEntry.eventTime, motionEntry.deviceId, + motionEntry.source, motionEntry.displayId, + motionEntry.policyFlags, resolvedAction, + motionEntry.actionButton, resolvedFlags, + motionEntry.metaState, motionEntry.buttonState, + motionEntry.classification, motionEntry.edgeFlags, + motionEntry.xPrecision, motionEntry.yPrecision, + motionEntry.xCursorPosition, motionEntry.yCursorPosition, + motionEntry.downTime, + usingProperties.value_or(motionEntry.pointerProperties), + usingCoords.value_or(motionEntry.pointerCoords)); if (ATRACE_ENABLED()) { std::string message = StringPrintf("Transmute MotionEvent(id=0x%" PRIx32 ") to MotionEvent(id=0x%" PRIx32 ").", @@ -4418,7 +4449,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) { policyFlags |= POLICY_FLAG_TRUSTED; android::base::Timer t; - mPolicy.interceptMotionBeforeQueueing(args.displayId, args.eventTime, policyFlags); + mPolicy.interceptMotionBeforeQueueing(args.displayId, args.source, args.action, args.eventTime, + policyFlags); if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms", std::to_string(t.duration().count()).c_str()); @@ -4679,7 +4711,9 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev if (!(policyFlags & POLICY_FLAG_FILTERED)) { nsecs_t eventTime = motionEvent.getEventTime(); android::base::Timer t; - mPolicy.interceptMotionBeforeQueueing(displayId, eventTime, /*byref*/ policyFlags); + mPolicy.interceptMotionBeforeQueueing(displayId, motionEvent.getSource(), + motionEvent.getAction(), eventTime, + /*byref*/ policyFlags); if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms", std::to_string(t.duration().count()).c_str()); @@ -5047,6 +5081,13 @@ bool InputDispatcher::canWindowReceiveMotionLocked(const sp<WindowInfoHandle>& w return false; } + // Ignore touches if stylus is down anywhere on screen + if (info.inputConfig.test(WindowInfo::InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH) && + isStylusActiveInDisplay(info.displayId, mTouchStatesByDisplay)) { + LOG(INFO) << "Dropping touch from " << window->getName() << " because stylus is active"; + return false; + } + return true; } @@ -5481,7 +5522,7 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< // Erase old window. ftl::Flags<InputTarget::Flags> oldTargetFlags = touchedWindow->targetFlags; - std::bitset<MAX_POINTER_ID + 1> pointerIds = touchedWindow->getTouchingPointers(deviceId); + std::vector<PointerProperties> pointers = touchedWindow->getTouchingPointers(deviceId); sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle; state->removeWindowByToken(fromToken); @@ -5493,17 +5534,17 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< newTargetFlags |= InputTarget::Flags::FOREGROUND; } state->addOrUpdateWindow(toWindowHandle, InputTarget::DispatchMode::AS_IS, newTargetFlags, - deviceId, pointerIds, downTimeInTarget); + deviceId, pointers, downTimeInTarget); // Store the dragging window. if (isDragDrop) { - if (pointerIds.count() != 1) { + if (pointers.size() != 1) { ALOGW("The drag and drop cannot be started when there is no pointer or more than 1" " pointer on the window."); return false; } // Track the pointer id for drag window and generate the drag state. - const size_t id = firstMarkedBit(pointerIds); + const size_t id = pointers.begin()->id; mDragState = std::make_unique<DragState>(toWindowHandle, id); } @@ -5520,7 +5561,7 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< // Check if the wallpaper window should deliver the corresponding event. transferWallpaperTouch(oldTargetFlags, newTargetFlags, fromWindowHandle, toWindowHandle, - *state, deviceId, pointerIds); + *state, deviceId, pointers); } } // release lock @@ -5997,8 +6038,10 @@ status_t InputDispatcher::pilferPointersLocked(const sp<IBinder>& token) { "input channel stole pointer stream"); options.deviceId = deviceId; options.displayId = displayId; - std::bitset<MAX_POINTER_ID + 1> pointerIds = window.getTouchingPointers(deviceId); + std::vector<PointerProperties> pointers = window.getTouchingPointers(deviceId); + std::bitset<MAX_POINTER_ID + 1> pointerIds = getPointerIds(pointers); options.pointerIds = pointerIds; + std::string canceledWindows; for (const TouchedWindow& w : state.windows) { const std::shared_ptr<InputChannel> channel = @@ -6794,10 +6837,10 @@ void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanosecon void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, const sp<WindowInfoHandle>& oldWindowHandle, const sp<WindowInfoHandle>& newWindowHandle, - TouchState& state, int32_t deviceId, int32_t pointerId, + TouchState& state, int32_t deviceId, + const PointerProperties& pointerProperties, std::vector<InputTarget>& targets) const { - std::bitset<MAX_POINTER_ID + 1> pointerIds; - pointerIds.set(pointerId); + std::vector<PointerProperties> pointers{pointerProperties}; const bool oldHasWallpaper = oldWindowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); const bool newHasWallpaper = targetFlags.test(InputTarget::Flags::FOREGROUND) && @@ -6814,16 +6857,16 @@ void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFl if (oldWallpaper != nullptr) { const TouchedWindow& oldTouchedWindow = state.getTouchedWindow(oldWallpaper); addPointerWindowTargetLocked(oldWallpaper, InputTarget::DispatchMode::SLIPPERY_EXIT, - oldTouchedWindow.targetFlags, pointerIds, + oldTouchedWindow.targetFlags, getPointerIds(pointers), oldTouchedWindow.getDownTimeInTarget(deviceId), targets); - state.removeTouchingPointerFromWindow(deviceId, pointerId, oldWallpaper); + state.removeTouchingPointerFromWindow(deviceId, pointerProperties.id, oldWallpaper); } if (newWallpaper != nullptr) { state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::SLIPPERY_ENTER, InputTarget::Flags::WINDOW_IS_OBSCURED | InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED, - deviceId, pointerIds); + deviceId, pointers); } } @@ -6832,7 +6875,7 @@ void InputDispatcher::transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldT const sp<WindowInfoHandle> fromWindowHandle, const sp<WindowInfoHandle> toWindowHandle, TouchState& state, int32_t deviceId, - std::bitset<MAX_POINTER_ID + 1> pointerIds) { + const std::vector<PointerProperties>& pointers) { const bool oldHasWallpaper = oldTargetFlags.test(InputTarget::Flags::FOREGROUND) && fromWindowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); @@ -6861,7 +6904,7 @@ void InputDispatcher::transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldT wallpaperFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED | InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED; state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::AS_IS, wallpaperFlags, - deviceId, pointerIds, downTimeInTarget); + deviceId, pointers, downTimeInTarget); std::shared_ptr<Connection> wallpaperConnection = getConnectionLocked(newWallpaper->getToken()); if (wallpaperConnection != nullptr) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 3f99b2d40e..010dbb28e4 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -690,14 +690,15 @@ private: void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, const sp<android::gui::WindowInfoHandle>& oldWindowHandle, const sp<android::gui::WindowInfoHandle>& newWindowHandle, - TouchState& state, int32_t deviceId, int32_t pointerId, + TouchState& state, int32_t deviceId, + const PointerProperties& pointerProperties, std::vector<InputTarget>& targets) const REQUIRES(mLock); void transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags, ftl::Flags<InputTarget::Flags> newTargetFlags, const sp<android::gui::WindowInfoHandle> fromWindowHandle, const sp<android::gui::WindowInfoHandle> toWindowHandle, TouchState& state, int32_t deviceId, - std::bitset<MAX_POINTER_ID + 1> pointerIds) REQUIRES(mLock); + const std::vector<PointerProperties>& pointers) REQUIRES(mLock); sp<android::gui::WindowInfoHandle> findWallpaperWindowBelow( const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock); diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index a4ac4fbe6c..1fec9b7599 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -195,6 +195,16 @@ bool InputState::trackMotion(const MotionEntry& entry, int32_t flags) { } } +std::optional<std::pair<std::vector<PointerProperties>, std::vector<PointerCoords>>> +InputState::getPointersOfLastEvent(const MotionEntry& entry, bool hovering) const { + ssize_t index = findMotionMemento(entry, hovering); + if (index == -1) { + return std::nullopt; + } + return std::make_pair(mMotionMementos[index].pointerProperties, + mMotionMementos[index].pointerCoords); +} + ssize_t InputState::findKeyMemento(const KeyEntry& entry) const { for (size_t i = 0; i < mKeyMementos.size(); i++) { const KeyMemento& memento = mKeyMementos[i]; @@ -311,16 +321,6 @@ bool InputState::shouldCancelPreviousStream(const MotionEntry& motionEntry) cons return true; } - // Use the previous stream cancellation logic to generate all HOVER_EXIT events. - // If this hover event was generated as a result of the pointer leaving the window, - // the HOVER_EXIT event should have the same coordinates as the previous - // HOVER_MOVE event in this stream. Ensure that all HOVER_EXITs have the same - // coordinates as the previous event by cancelling the stream here. With this approach, the - // HOVER_EXIT event is generated from the previous event. - if (actionMasked == AMOTION_EVENT_ACTION_HOVER_EXIT && lastMemento.hovering) { - return true; - } - // If the stream changes its source, just cancel the current gesture to be safe. It's // possible that the app isn't handling source changes properly if (motionEntry.source != lastMemento.source) { diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h index b0e4209882..d49469ddc1 100644 --- a/services/inputflinger/dispatcher/InputState.h +++ b/services/inputflinger/dispatcher/InputState.h @@ -48,6 +48,15 @@ public: // and should be skipped. bool trackMotion(const MotionEntry& entry, int32_t flags); + /** + * Return the PointerProperties and the PointerCoords for the last event, if found. Return + * std::nullopt if not found. We should not return std::vector<PointerCoords> in isolation, + * because the pointers can technically be stored in the vector in any order, so the + * PointerProperties are needed to specify the order in which the pointer coords are stored. + */ + std::optional<std::pair<std::vector<PointerProperties>, std::vector<PointerCoords>>> + getPointersOfLastEvent(const MotionEntry& entry, bool hovering) const; + // Create cancel events for the previous stream if the current motionEntry requires it. std::unique_ptr<EventEntry> cancelConflictingInputStream(const MotionEntry& motionEntry); diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index e8d8c18e4e..f8aa62500e 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -73,9 +73,9 @@ void TouchState::clearWindowsWithoutPointers() { void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId, - std::bitset<MAX_POINTER_ID + 1> touchingPointerIds, + const std::vector<PointerProperties>& touchingPointers, std::optional<nsecs_t> firstDownTimeInTarget) { - if (touchingPointerIds.none()) { + if (touchingPointers.empty()) { LOG(FATAL) << __func__ << "No pointers specified for " << windowHandle->getName(); return; } @@ -91,7 +91,7 @@ void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have // downTime set initially. Need to update existing window when a pointer is down for the // window. - touchedWindow.addTouchingPointers(deviceId, touchingPointerIds); + touchedWindow.addTouchingPointers(deviceId, touchingPointers); if (firstDownTimeInTarget) { touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget); } @@ -102,7 +102,7 @@ void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, touchedWindow.windowHandle = windowHandle; touchedWindow.dispatchMode = dispatchMode; touchedWindow.targetFlags = targetFlags; - touchedWindow.addTouchingPointers(deviceId, touchingPointerIds); + touchedWindow.addTouchingPointers(deviceId, touchingPointers); if (firstDownTimeInTarget) { touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget); } @@ -110,17 +110,17 @@ void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, } void TouchState::addHoveringPointerToWindow(const sp<WindowInfoHandle>& windowHandle, - DeviceId deviceId, int32_t hoveringPointerId) { + DeviceId deviceId, const PointerProperties& pointer) { for (TouchedWindow& touchedWindow : windows) { if (touchedWindow.windowHandle == windowHandle) { - touchedWindow.addHoveringPointer(deviceId, hoveringPointerId); + touchedWindow.addHoveringPointer(deviceId, pointer); return; } } TouchedWindow touchedWindow; touchedWindow.windowHandle = windowHandle; - touchedWindow.addHoveringPointer(deviceId, hoveringPointerId); + touchedWindow.addHoveringPointer(deviceId, pointer); windows.push_back(touchedWindow); } @@ -234,6 +234,11 @@ bool TouchState::hasHoveringPointers(DeviceId deviceId) const { }); } +bool TouchState::hasActiveStylus() const { + return std::any_of(windows.begin(), windows.end(), + [](const TouchedWindow& window) { return window.hasActiveStylus(); }); +} + std::set<sp<WindowInfoHandle>> TouchState::getWindowsWithHoveringPointer(DeviceId deviceId, int32_t pointerId) const { std::set<sp<WindowInfoHandle>> out; diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index e0a84e8f45..3d534bc71d 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -46,11 +46,11 @@ struct TouchState { void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle, InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId, - std::bitset<MAX_POINTER_ID + 1> touchingPointerIds, + const std::vector<PointerProperties>& touchingPointers, std::optional<nsecs_t> firstDownTimeInTarget = std::nullopt); void addHoveringPointerToWindow(const sp<android::gui::WindowInfoHandle>& windowHandle, - DeviceId deviceId, int32_t hoveringPointerId); - void removeHoveringPointer(DeviceId deviceId, int32_t hoveringPointerId); + DeviceId deviceId, const PointerProperties& pointer); + void removeHoveringPointer(DeviceId deviceId, int32_t pointerId); void clearHoveringPointers(DeviceId deviceId); void removeAllPointersForDevice(DeviceId deviceId); @@ -73,6 +73,8 @@ struct TouchState { bool isDown(DeviceId deviceId) const; bool hasHoveringPointers(DeviceId deviceId) const; + bool hasActiveStylus() const; + std::set<sp<android::gui::WindowInfoHandle>> getWindowsWithHoveringPointer( DeviceId deviceId, int32_t pointerId) const; std::string dump() const; diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp index cd0500c872..037d7c8e99 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.cpp +++ b/services/inputflinger/dispatcher/TouchedWindow.cpp @@ -26,9 +26,20 @@ namespace android { namespace inputdispatcher { +namespace { + +bool hasPointerId(const std::vector<PointerProperties>& pointers, int32_t pointerId) { + return std::find_if(pointers.begin(), pointers.end(), + [&pointerId](const PointerProperties& properties) { + return properties.id == pointerId; + }) != pointers.end(); +} + +} // namespace + bool TouchedWindow::hasHoveringPointers() const { for (const auto& [_, state] : mDeviceStates) { - if (state.hoveringPointerIds.any()) { + if (!state.hoveringPointers.empty()) { return true; } } @@ -42,7 +53,7 @@ bool TouchedWindow::hasHoveringPointers(DeviceId deviceId) const { } const DeviceState& state = stateIt->second; - return state.hoveringPointerIds.any(); + return !state.hoveringPointers.empty(); } void TouchedWindow::clearHoveringPointers(DeviceId deviceId) { @@ -51,7 +62,7 @@ void TouchedWindow::clearHoveringPointers(DeviceId deviceId) { return; } DeviceState& state = stateIt->second; - state.hoveringPointerIds.reset(); + state.hoveringPointers.clear(); if (!state.hasPointers()) { mDeviceStates.erase(stateIt); } @@ -63,22 +74,40 @@ bool TouchedWindow::hasHoveringPointer(DeviceId deviceId, int32_t pointerId) con return false; } const DeviceState& state = stateIt->second; - - return state.hoveringPointerIds.test(pointerId); + return hasPointerId(state.hoveringPointers, pointerId); } -void TouchedWindow::addHoveringPointer(DeviceId deviceId, int32_t pointerId) { - mDeviceStates[deviceId].hoveringPointerIds.set(pointerId); +void TouchedWindow::addHoveringPointer(DeviceId deviceId, const PointerProperties& pointer) { + std::vector<PointerProperties>& hoveringPointers = mDeviceStates[deviceId].hoveringPointers; + const size_t initialSize = hoveringPointers.size(); + std::erase_if(hoveringPointers, [&pointer](const PointerProperties& properties) { + return properties.id == pointer.id; + }); + if (hoveringPointers.size() != initialSize) { + LOG(ERROR) << __func__ << ": " << pointer << ", device " << deviceId << " was in " << *this; + } + hoveringPointers.push_back(pointer); } void TouchedWindow::addTouchingPointers(DeviceId deviceId, - std::bitset<MAX_POINTER_ID + 1> pointers) { - mDeviceStates[deviceId].touchingPointerIds |= pointers; + const std::vector<PointerProperties>& pointers) { + std::vector<PointerProperties>& touchingPointers = mDeviceStates[deviceId].touchingPointers; + const size_t initialSize = touchingPointers.size(); + for (const PointerProperties& pointer : pointers) { + std::erase_if(touchingPointers, [&pointer](const PointerProperties& properties) { + return properties.id == pointer.id; + }); + } + if (touchingPointers.size() != initialSize) { + LOG(ERROR) << __func__ << ": " << dumpVector(pointers, streamableToString) << ", device " + << deviceId << " already in " << *this; + } + touchingPointers.insert(touchingPointers.end(), pointers.begin(), pointers.end()); } bool TouchedWindow::hasTouchingPointers() const { for (const auto& [_, state] : mDeviceStates) { - if (state.touchingPointerIds.any()) { + if (!state.touchingPointers.empty()) { return true; } } @@ -86,21 +115,25 @@ bool TouchedWindow::hasTouchingPointers() const { } bool TouchedWindow::hasTouchingPointers(DeviceId deviceId) const { - return getTouchingPointers(deviceId).any(); + return !getTouchingPointers(deviceId).empty(); } bool TouchedWindow::hasTouchingPointer(DeviceId deviceId, int32_t pointerId) const { - return getTouchingPointers(deviceId).test(pointerId); + const auto stateIt = mDeviceStates.find(deviceId); + if (stateIt == mDeviceStates.end()) { + return false; + } + const DeviceState& state = stateIt->second; + return hasPointerId(state.touchingPointers, pointerId); } -std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getTouchingPointers(DeviceId deviceId) const { +std::vector<PointerProperties> TouchedWindow::getTouchingPointers(DeviceId deviceId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return {}; } const DeviceState& state = stateIt->second; - - return state.touchingPointerIds; + return state.touchingPointers; } void TouchedWindow::removeTouchingPointer(DeviceId deviceId, int32_t pointerId) { @@ -118,7 +151,10 @@ void TouchedWindow::removeTouchingPointers(DeviceId deviceId, } DeviceState& state = stateIt->second; - state.touchingPointerIds &= ~pointers; + std::erase_if(state.touchingPointers, [&pointers](const PointerProperties& properties) { + return pointers.test(properties.id); + }); + state.pilferingPointerIds &= ~pointers; if (!state.hasPointers()) { @@ -126,10 +162,26 @@ void TouchedWindow::removeTouchingPointers(DeviceId deviceId, } } +bool TouchedWindow::hasActiveStylus() const { + for (const auto& [_, state] : mDeviceStates) { + for (const PointerProperties& properties : state.touchingPointers) { + if (properties.toolType == ToolType::STYLUS) { + return true; + } + } + for (const PointerProperties& properties : state.hoveringPointers) { + if (properties.toolType == ToolType::STYLUS) { + return true; + } + } + } + return false; +} + std::set<DeviceId> TouchedWindow::getTouchingDeviceIds() const { std::set<DeviceId> deviceIds; for (const auto& [deviceId, deviceState] : mDeviceStates) { - if (deviceState.touchingPointerIds.any()) { + if (!deviceState.touchingPointers.empty()) { deviceIds.insert(deviceId); } } @@ -198,7 +250,7 @@ void TouchedWindow::removeAllTouchingPointersForDevice(DeviceId deviceId) { } DeviceState& state = stateIt->second; - state.touchingPointerIds.reset(); + state.touchingPointers.clear(); state.pilferingPointerIds.reset(); state.downTimeInTarget.reset(); @@ -214,7 +266,9 @@ void TouchedWindow::removeHoveringPointer(DeviceId deviceId, int32_t pointerId) } DeviceState& state = stateIt->second; - state.hoveringPointerIds.set(pointerId, false); + std::erase_if(state.hoveringPointers, [&pointerId](const PointerProperties& properties) { + return properties.id == pointerId; + }); if (!state.hasPointers()) { mDeviceStates.erase(stateIt); @@ -228,7 +282,7 @@ void TouchedWindow::removeAllHoveringPointersForDevice(DeviceId deviceId) { } DeviceState& state = stateIt->second; - state.hoveringPointerIds.reset(); + state.hoveringPointers.clear(); if (!state.hasPointers()) { mDeviceStates.erase(stateIt); @@ -236,11 +290,11 @@ void TouchedWindow::removeAllHoveringPointersForDevice(DeviceId deviceId) { } std::string TouchedWindow::deviceStateToString(const TouchedWindow::DeviceState& state) { - return StringPrintf("[touchingPointerIds=%s, " - "downTimeInTarget=%s, hoveringPointerIds=%s, pilferingPointerIds=%s]", - bitsetToString(state.touchingPointerIds).c_str(), + return StringPrintf("[touchingPointers=%s, " + "downTimeInTarget=%s, hoveringPointers=%s, pilferingPointerIds=%s]", + dumpVector(state.touchingPointers, streamableToString).c_str(), toString(state.downTimeInTarget).c_str(), - bitsetToString(state.hoveringPointerIds).c_str(), + dumpVector(state.hoveringPointers, streamableToString).c_str(), bitsetToString(state.pilferingPointerIds).c_str()); } diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h index c604353593..0d1531f8ff 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ b/services/inputflinger/dispatcher/TouchedWindow.h @@ -38,17 +38,18 @@ struct TouchedWindow { bool hasHoveringPointers() const; bool hasHoveringPointers(DeviceId deviceId) const; bool hasHoveringPointer(DeviceId deviceId, int32_t pointerId) const; - void addHoveringPointer(DeviceId deviceId, int32_t pointerId); + void addHoveringPointer(DeviceId deviceId, const PointerProperties& pointer); void removeHoveringPointer(DeviceId deviceId, int32_t pointerId); // Touching bool hasTouchingPointer(DeviceId deviceId, int32_t pointerId) const; bool hasTouchingPointers() const; bool hasTouchingPointers(DeviceId deviceId) const; - std::bitset<MAX_POINTER_ID + 1> getTouchingPointers(DeviceId deviceId) const; - void addTouchingPointers(DeviceId deviceId, std::bitset<MAX_POINTER_ID + 1> pointers); + std::vector<PointerProperties> getTouchingPointers(DeviceId deviceId) const; + void addTouchingPointers(DeviceId deviceId, const std::vector<PointerProperties>& pointers); void removeTouchingPointer(DeviceId deviceId, int32_t pointerId); void removeTouchingPointers(DeviceId deviceId, std::bitset<MAX_POINTER_ID + 1> pointers); + bool hasActiveStylus() const; std::set<DeviceId> getTouchingDeviceIds() const; // Pilfering pointers @@ -69,16 +70,16 @@ struct TouchedWindow { private: struct DeviceState { - std::bitset<MAX_POINTER_ID + 1> touchingPointerIds; + std::vector<PointerProperties> touchingPointers; // The pointer ids of the pointers that this window is currently pilfering, by device std::bitset<MAX_POINTER_ID + 1> pilferingPointerIds; // Time at which the first action down occurred on this window, for each device // NOTE: This is not initialized in case of HOVER entry/exit and DISPATCH_AS_OUTSIDE // scenario. std::optional<nsecs_t> downTimeInTarget; - std::bitset<MAX_POINTER_ID + 1> hoveringPointerIds; + std::vector<PointerProperties> hoveringPointers; - bool hasPointers() const { return touchingPointerIds.any() || hoveringPointerIds.any(); }; + bool hasPointers() const { return !touchingPointers.empty() || !hoveringPointers.empty(); }; }; std::map<DeviceId, DeviceState> mDeviceStates; diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h index 1c23720ecb..9e6209b3d9 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h @@ -99,8 +99,8 @@ public: * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event * should be dispatched to applications. */ - virtual void interceptMotionBeforeQueueing(int32_t displayId, nsecs_t when, - uint32_t& policyFlags) = 0; + virtual void interceptMotionBeforeQueueing(int32_t displayId, uint32_t source, int32_t action, + nsecs_t when, uint32_t& policyFlags) = 0; /* Allows the policy a chance to intercept a key before dispatching. */ virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token, diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp index 5a74a42446..2dd05f5c66 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp @@ -35,10 +35,12 @@ MultiTouchInputMapper::MultiTouchInputMapper(InputDeviceContext& deviceContext, MultiTouchInputMapper::~MultiTouchInputMapper() {} std::list<NotifyArgs> MultiTouchInputMapper::reset(nsecs_t when) { - // TODO(b/291626046): Sync the MT state with the kernel using EVIOCGMTSLOTS. - mMultiTouchMotionAccumulator.reset(getDeviceContext()); - mPointerIdBits.clear(); - + // The evdev multi-touch protocol does not allow userspace applications to query the initial or + // current state of the pointers at any time. This means if we clear our accumulated state when + // resetting the input mapper, there's no way to rebuild the full initial state of the pointers. + // We can only wait for updates to all the pointers and axes. Rather than clearing the state and + // rebuilding the state from scratch, we work around this kernel API limitation by never + // fully clearing any state specific to the multi-touch protocol. return TouchInputMapper::reset(when); } diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp index 34ca0b3767..255f02d278 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp @@ -21,9 +21,11 @@ #include <iterator> #include <limits> #include <map> +#include <mutex> #include <optional> #include <android-base/stringprintf.h> +#include <android-base/thread_annotations.h> #include <android/input.h> #include <com_android_input_flags.h> #include <ftl/enum.h> @@ -156,13 +158,20 @@ public: return sAccumulator; } - void recordFinger(const TouchpadInputMapper::MetricsIdentifier& id) { mCounters[id].fingers++; } + void recordFinger(const TouchpadInputMapper::MetricsIdentifier& id) { + std::scoped_lock lock(mLock); + mCounters[id].fingers++; + } - void recordPalm(const TouchpadInputMapper::MetricsIdentifier& id) { mCounters[id].palms++; } + void recordPalm(const TouchpadInputMapper::MetricsIdentifier& id) { + std::scoped_lock lock(mLock); + mCounters[id].palms++; + } // Checks whether a Gesture struct is for the end of a gesture that we log metrics for, and // records it if so. void processGesture(const TouchpadInputMapper::MetricsIdentifier& id, const Gesture& gesture) { + std::scoped_lock lock(mLock); switch (gesture.type) { case kGestureTypeFling: if (gesture.details.fling.fling_state == GESTURES_FLING_START) { @@ -200,15 +209,20 @@ private: void* cookie) { LOG_ALWAYS_FATAL_IF(atomTag != android::util::TOUCHPAD_USAGE); MetricsAccumulator& accumulator = MetricsAccumulator::getInstance(); - accumulator.produceAtoms(outEventList); - accumulator.resetCounters(); + accumulator.produceAtomsAndReset(*outEventList); return AStatsManager_PULL_SUCCESS; } - void produceAtoms(AStatsEventList* outEventList) const { + void produceAtomsAndReset(AStatsEventList& outEventList) { + std::scoped_lock lock(mLock); + produceAtomsLocked(outEventList); + resetCountersLocked(); + } + + void produceAtomsLocked(AStatsEventList& outEventList) const REQUIRES(mLock) { for (auto& [id, counters] : mCounters) { auto [busId, vendorId, productId, versionId] = id; - addAStatsEvent(outEventList, android::util::TOUCHPAD_USAGE, vendorId, productId, + addAStatsEvent(&outEventList, android::util::TOUCHPAD_USAGE, vendorId, productId, versionId, linuxBusToInputDeviceBusEnum(busId, /*isUsi=*/false), counters.fingers, counters.palms, counters.twoFingerSwipeGestures, counters.threeFingerSwipeGestures, counters.fourFingerSwipeGestures, @@ -216,7 +230,7 @@ private: } } - void resetCounters() { mCounters.clear(); } + void resetCountersLocked() REQUIRES(mLock) { mCounters.clear(); } // Stores the counters for a specific touchpad model. Fields have the same meanings as those of // the TouchpadUsage atom; see that definition for detailed documentation. @@ -232,7 +246,10 @@ private: // Metrics are aggregated by device model and version, so if two devices of the same model and // version are connected at once, they will have the same counters. - std::map<TouchpadInputMapper::MetricsIdentifier, Counters> mCounters; + std::map<TouchpadInputMapper::MetricsIdentifier, Counters> mCounters GUARDED_BY(mLock); + + // Metrics are pulled by a binder thread, so we need to guard them with a mutex. + mutable std::mutex mLock; }; } // namespace @@ -449,6 +466,9 @@ std::list<NotifyArgs> TouchpadInputMapper::process(const RawEvent* rawEvent) { if (mPointerCaptured) { return mCapturedEventConverter.process(*rawEvent); } + if (mMotionAccumulator.getActiveSlotsCount() == 0) { + mGestureStartTime = rawEvent->when; + } std::optional<SelfContainedHardwareState> state = mStateConverter.processRawEvent(rawEvent); if (state) { updatePalmDetectionMetrics(); @@ -514,7 +534,7 @@ std::list<NotifyArgs> TouchpadInputMapper::processGestures(nsecs_t when, nsecs_t if (mDisplayId) { MetricsAccumulator& metricsAccumulator = MetricsAccumulator::getInstance(); for (Gesture& gesture : mGesturesToProcess) { - out += mGestureConverter.handleGesture(when, readTime, gesture); + out += mGestureConverter.handleGesture(when, readTime, mGestureStartTime, gesture); metricsAccumulator.processGesture(mMetricsId, gesture); } } diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h index ece0eca0e7..897edca4e1 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h @@ -113,6 +113,8 @@ private: // ADISPLAY_ID_NONE to target the focused display. If there is no display target (i.e. // std::nullopt), all events will be ignored. std::optional<int32_t> mDisplayId; + + nsecs_t mGestureStartTime{0}; }; } // namespace android diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp index d06514acab..b0fc9035f2 100644 --- a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp +++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp @@ -30,29 +30,23 @@ void MultiTouchMotionAccumulator::configure(const InputDeviceContext& deviceCont size_t slotCount, bool usingSlotsProtocol) { mUsingSlotsProtocol = usingSlotsProtocol; mSlots = std::vector<Slot>(slotCount); - reset(deviceContext); -} - -void MultiTouchMotionAccumulator::reset(const InputDeviceContext& deviceContext) { - resetSlots(); - - if (!mUsingSlotsProtocol) { - return; - } - // Query the driver for the current slot index and use it as the initial slot before we - // start reading events from the device. It is possible that the current slot index will - // not be the same as it was when the first event was written into the evdev buffer, which - // means the input mapper could start out of sync with the initial state of the events in - // the evdev buffer. In the extremely unlikely case that this happens, the data from two - // slots will be confused until the next ABS_MT_SLOT event is received. This can cause the - // touch point to "jump", but at least there will be no stuck touches. - int32_t initialSlot; - if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot); - status == OK) { - mCurrentSlot = initialSlot; - } else { - ALOGD("Could not retrieve current multi-touch slot index. status=%d", status); + mCurrentSlot = -1; + if (mUsingSlotsProtocol) { + // Query the driver for the current slot index and use it as the initial slot before we + // start reading events from the device. It is possible that the current slot index will + // not be the same as it was when the first event was written into the evdev buffer, which + // means the input mapper could start out of sync with the initial state of the events in + // the evdev buffer. In the extremely unlikely case that this happens, the data from two + // slots will be confused until the next ABS_MT_SLOT event is received. This can cause the + // touch point to "jump", but at least there will be no stuck touches. + int32_t initialSlot; + if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot); + status == OK) { + mCurrentSlot = initialSlot; + } else { + ALOGD("Could not retrieve current multi-touch slot index. status=%d", status); + } } } diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h index 5b55e3d599..0e3e2bb365 100644 --- a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h +++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h @@ -83,7 +83,6 @@ public: LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index); return mSlots[index]; } - void reset(const InputDeviceContext& deviceContext); private: int32_t mCurrentSlot; diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp index 955210479f..01e983a371 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp @@ -35,8 +35,14 @@ namespace android { namespace { +// This will disable the tap to click while the user is typing on a physical keyboard const bool ENABLE_TOUCHPAD_PALM_REJECTION = input_flags::enable_touchpad_typing_palm_rejection(); +// In addition to v1, v2 will also cancel ongoing move gestures while typing and add delay in +// re-enabling the tap to click. +const bool ENABLE_TOUCHPAD_PALM_REJECTION_V2 = + input_flags::enable_v2_touchpad_typing_palm_rejection(); + uint32_t gesturesButtonToMotionEventButton(uint32_t gesturesButton) { switch (gesturesButton) { case GESTURES_BUTTON_LEFT: @@ -75,6 +81,7 @@ std::string GestureConverter::dump() const { out << StringPrintf("Button state: 0x%08x\n", mButtonState); out << "Down time: " << mDownTime << "\n"; out << "Current classification: " << ftl::enum_string(mCurrentClassification) << "\n"; + out << "Enable Tap Timestamp: " << mWhenToEnableTapToClick << "\n"; return out.str(); } @@ -109,8 +116,6 @@ std::list<NotifyArgs> GestureConverter::reset(nsecs_t when) { void GestureConverter::populateMotionRanges(InputDeviceInfo& info) const { info.addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, SOURCE, 0.0f, 1.0f, 0, 0, 0); - // TODO(b/259547750): set this using the raw axis ranges from the touchpad when pointer capture - // is enabled. if (!mBoundsInLogicalDisplay.isEmpty()) { info.addMotionRange(AMOTION_EVENT_AXIS_X, SOURCE, mBoundsInLogicalDisplay.left, mBoundsInLogicalDisplay.right, 0, 0, 0); @@ -131,6 +136,7 @@ void GestureConverter::populateMotionRanges(InputDeviceInfo& info) const { } std::list<NotifyArgs> GestureConverter::handleGesture(nsecs_t when, nsecs_t readTime, + nsecs_t gestureStartTime, const Gesture& gesture) { if (!mDisplayId) { // Ignore gestures when there is no target display configured. @@ -139,13 +145,13 @@ std::list<NotifyArgs> GestureConverter::handleGesture(nsecs_t when, nsecs_t read switch (gesture.type) { case kGestureTypeMove: - return {handleMove(when, readTime, gesture)}; + return handleMove(when, readTime, gestureStartTime, gesture); case kGestureTypeButtonsChange: return handleButtonsChange(when, readTime, gesture); case kGestureTypeScroll: return handleScroll(when, readTime, gesture); case kGestureTypeFling: - return handleFling(when, readTime, gesture); + return handleFling(when, readTime, gestureStartTime, gesture); case kGestureTypeSwipe: return handleMultiFingerSwipe(when, readTime, 3, gesture.details.swipe.dx, gesture.details.swipe.dy); @@ -162,18 +168,41 @@ std::list<NotifyArgs> GestureConverter::handleGesture(nsecs_t when, nsecs_t read } } -NotifyMotionArgs GestureConverter::handleMove(nsecs_t when, nsecs_t readTime, - const Gesture& gesture) { +std::list<NotifyArgs> GestureConverter::handleMove(nsecs_t when, nsecs_t readTime, + nsecs_t gestureStartTime, + const Gesture& gesture) { float deltaX = gesture.details.move.dx; float deltaY = gesture.details.move.dy; - if (ENABLE_TOUCHPAD_PALM_REJECTION && (std::abs(deltaX) > 0 || std::abs(deltaY) > 0)) { - enableTapToClick(); + if (ENABLE_TOUCHPAD_PALM_REJECTION_V2) { + bool wasHoverCancelled = mIsHoverCancelled; + // Gesture will be cancelled if it started before the user started typing and + // there is a active IME connection. + mIsHoverCancelled = gestureStartTime <= mReaderContext.getLastKeyDownTimestamp() && + mReaderContext.getPolicy()->isInputMethodConnectionActive(); + + if (!wasHoverCancelled && mIsHoverCancelled) { + // This is the first event of the cancelled gesture, we won't return because we need to + // generate a HOVER_EXIT event + mPointerController->fade(PointerControllerInterface::Transition::GRADUAL); + } else if (mIsHoverCancelled) { + return {}; + } } + rotateDelta(mOrientation, &deltaX, &deltaY); - mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); - mPointerController->move(deltaX, deltaY); - mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE); + // Update the cursor, and enable tap to click if the gesture is not cancelled + if (!mIsHoverCancelled) { + // handleFling calls hoverMove with zero delta on FLING_TAP_DOWN. Don't enable tap to click + // for this case as subsequent handleButtonsChange may choose to ignore this tap. + if ((ENABLE_TOUCHPAD_PALM_REJECTION || ENABLE_TOUCHPAD_PALM_REJECTION_V2) && + (std::abs(deltaX) > 0 || std::abs(deltaY) > 0)) { + enableTapToClick(when); + } + mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); + mPointerController->move(deltaX, deltaY); + mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE); + } const auto [xCursorPosition, yCursorPosition] = mEnablePointerChoreographer ? FloatPoint{0, 0} : mPointerController->getPosition(); @@ -187,10 +216,12 @@ NotifyMotionArgs GestureConverter::handleMove(nsecs_t when, nsecs_t readTime, const bool down = isPointerDown(mButtonState); coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); - const int32_t action = down ? AMOTION_EVENT_ACTION_MOVE : AMOTION_EVENT_ACTION_HOVER_MOVE; - return makeMotionArgs(when, readTime, action, /* actionButton= */ 0, mButtonState, - /* pointerCount= */ 1, mFingerProps.data(), &coords, xCursorPosition, - yCursorPosition); + const int32_t action = mIsHoverCancelled + ? AMOTION_EVENT_ACTION_HOVER_EXIT + : (down ? AMOTION_EVENT_ACTION_MOVE : AMOTION_EVENT_ACTION_HOVER_MOVE); + return {makeMotionArgs(when, readTime, action, /* actionButton= */ 0, mButtonState, + /* pointerCount= */ 1, mFingerProps.data(), &coords, xCursorPosition, + yCursorPosition)}; } std::list<NotifyArgs> GestureConverter::handleButtonsChange(nsecs_t when, nsecs_t readTime, @@ -210,8 +241,15 @@ std::list<NotifyArgs> GestureConverter::handleButtonsChange(nsecs_t when, nsecs_ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0); coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0); - if (ENABLE_TOUCHPAD_PALM_REJECTION && mReaderContext.isPreventingTouchpadTaps()) { - enableTapToClick(); + // V2 palm rejection should override V1 + if (ENABLE_TOUCHPAD_PALM_REJECTION_V2) { + enableTapToClick(when); + if (gesture.details.buttons.is_tap && when <= mWhenToEnableTapToClick) { + // return early to prevent this tap + return out; + } + } else if (ENABLE_TOUCHPAD_PALM_REJECTION && mReaderContext.isPreventingTouchpadTaps()) { + enableTapToClick(when); if (gesture.details.buttons.is_tap) { // return early to prevent this tap return out; @@ -348,6 +386,7 @@ std::list<NotifyArgs> GestureConverter::handleScroll(nsecs_t when, nsecs_t readT } std::list<NotifyArgs> GestureConverter::handleFling(nsecs_t when, nsecs_t readTime, + nsecs_t gestureStartTime, const Gesture& gesture) { switch (gesture.details.fling.fling_state) { case GESTURES_FLING_START: @@ -366,13 +405,10 @@ 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, - /*dy=*/0.f))}; + return handleMove(when, readTime, gestureStartTime, + Gesture(kGestureMove, gesture.start_time, gesture.end_time, + /*dx=*/0.f, + /*dy=*/0.f)); } break; default: @@ -598,8 +634,11 @@ NotifyMotionArgs GestureConverter::makeMotionArgs(nsecs_t when, nsecs_t readTime /* videoFrames= */ {}}; } -void GestureConverter::enableTapToClick() { - mReaderContext.setPreventingTouchpadTaps(false); +void GestureConverter::enableTapToClick(nsecs_t when) { + if (mReaderContext.isPreventingTouchpadTaps()) { + mWhenToEnableTapToClick = when + TAP_ENABLE_DELAY_NANOS.count(); + mReaderContext.setPreventingTouchpadTaps(false); + } } } // namespace android diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h index 732a4b2ffb..88e7b99877 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h @@ -34,6 +34,13 @@ namespace android { +using std::chrono_literals::operator""ms; +/** + * This duration is decided based on internal team testing, it may be updated after testing with + * larger groups + */ +constexpr std::chrono::nanoseconds TAP_ENABLE_DELAY_NANOS = 400ms; + // Converts Gesture structs from the gestures library into NotifyArgs and the appropriate // PointerController calls. class GestureConverter { @@ -53,17 +60,20 @@ public: void populateMotionRanges(InputDeviceInfo& info) const; [[nodiscard]] std::list<NotifyArgs> handleGesture(nsecs_t when, nsecs_t readTime, + nsecs_t gestureStartTime, const Gesture& gesture); private: - [[nodiscard]] NotifyMotionArgs handleMove(nsecs_t when, nsecs_t readTime, - const Gesture& gesture); + [[nodiscard]] std::list<NotifyArgs> handleMove(nsecs_t when, nsecs_t readTime, + nsecs_t gestureStartTime, + const Gesture& gesture); [[nodiscard]] std::list<NotifyArgs> handleButtonsChange(nsecs_t when, nsecs_t readTime, const Gesture& gesture); [[nodiscard]] std::list<NotifyArgs> releaseAllButtons(nsecs_t when, nsecs_t readTime); [[nodiscard]] std::list<NotifyArgs> handleScroll(nsecs_t when, nsecs_t readTime, const Gesture& gesture); [[nodiscard]] std::list<NotifyArgs> handleFling(nsecs_t when, nsecs_t readTime, + nsecs_t gestureStartTime, const Gesture& gesture); [[nodiscard]] NotifyMotionArgs endScroll(nsecs_t when, nsecs_t readTime); @@ -82,7 +92,9 @@ private: const PointerCoords* pointerCoords, float xCursorPosition, float yCursorPosition); - void enableTapToClick(); + void enableTapToClick(nsecs_t when); + bool mIsHoverCancelled{false}; + nsecs_t mWhenToEnableTapToClick{0}; const int32_t mDeviceId; InputReaderContext& mReaderContext; diff --git a/services/inputflinger/tests/FakeInputDispatcherPolicy.h b/services/inputflinger/tests/FakeInputDispatcherPolicy.h index e9d93af67b..fb2db06aff 100644 --- a/services/inputflinger/tests/FakeInputDispatcherPolicy.h +++ b/services/inputflinger/tests/FakeInputDispatcherPolicy.h @@ -63,7 +63,7 @@ private: void interceptKeyBeforeQueueing(const KeyEvent&, uint32_t&) override {} - void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) override {} + void interceptMotionBeforeQueueing(int32_t, uint32_t, int32_t, nsecs_t, uint32_t&) override {} nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent&, uint32_t) override { return 0; diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp index d2b68dd93e..69772af6b3 100644 --- a/services/inputflinger/tests/GestureConverter_test.cpp +++ b/services/inputflinger/tests/GestureConverter_test.cpp @@ -41,10 +41,14 @@ namespace { const auto TOUCHPAD_PALM_REJECTION = ACONFIG_FLAG(input_flags, enable_touchpad_typing_palm_rejection); +const auto TOUCHPAD_PALM_REJECTION_V2 = + ACONFIG_FLAG(input_flags, enable_v2_touchpad_typing_palm_rejection); } // namespace using testing::AllOf; +using testing::ElementsAre; +using testing::VariantWith; class GestureConverterTestBase : public testing::Test { protected: @@ -107,14 +111,14 @@ TEST_F(GestureConverterTest, Move) { converter.setDisplayId(ADISPLAY_ID_DEFAULT); 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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + 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), WithDisplayId(ADISPLAY_ID_DEFAULT))))); ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 5, POINTER_Y + 10)); } @@ -126,14 +130,14 @@ TEST_F(GestureConverterTest, Move_Rotated) { converter.setDisplayId(ADISPLAY_ID_DEFAULT); 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 + 10, POINTER_Y + 5), WithRelativeMotion(10, 5), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X + 10, POINTER_Y + 5), WithRelativeMotion(10, 5), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))))); ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X + 10, POINTER_Y + 5)); } @@ -147,67 +151,69 @@ TEST_F(GestureConverterTest, ButtonsChange) { Gesture downGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* down= */ GESTURES_BUTTON_LEFT | GESTURES_BUTTON_RIGHT, /* up= */ GESTURES_BUTTON_NONE, /* is_tap= */ false); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, downGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, downGesture); ASSERT_EQ(3u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | - AMOTION_EVENT_BUTTON_SECONDARY), - WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), - WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | - AMOTION_EVENT_BUTTON_SECONDARY), - WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | + AMOTION_EVENT_BUTTON_SECONDARY), + WithCoords(POINTER_X, POINTER_Y), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithCoords(POINTER_X, POINTER_Y), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | + AMOTION_EVENT_BUTTON_SECONDARY), + WithCoords(POINTER_X, POINTER_Y), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); // Then release the left button Gesture leftUpGesture(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, leftUpGesture); - ASSERT_EQ(1u, args.size()); - - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), - WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), - WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, leftUpGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), + WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); // Finally release the right button Gesture rightUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* down= */ GESTURES_BUTTON_NONE, /* up= */ GESTURES_BUTTON_RIGHT, /* is_tap= */ false); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, rightUpGesture); - ASSERT_EQ(3u, args.size()); - - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(0), - WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0), - WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithButtonState(0), - WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, rightUpGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), + WithButtonState(0), WithCoords(POINTER_X, POINTER_Y), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithButtonState(0), WithCoords(POINTER_X, POINTER_Y), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithButtonState(0), WithCoords(POINTER_X, POINTER_Y), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, DragWithButton) { @@ -219,32 +225,33 @@ TEST_F(GestureConverterTest, DragWithButton) { Gesture downGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* down= */ GESTURES_BUTTON_LEFT, /* up= */ GESTURES_BUTTON_NONE, /* is_tap= */ false); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, downGesture); - ASSERT_EQ(2u, args.size()); - - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), - WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, downGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithCoords(POINTER_X, POINTER_Y), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithCoords(POINTER_X, POINTER_Y), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); // Move Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); - 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_MOVE), - WithCoords(POINTER_X - 5, POINTER_Y + 10), WithRelativeMotion(-5, 10), - WithToolType(ToolType::FINGER), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), - WithPressure(1.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithCoords(POINTER_X - 5, POINTER_Y + 10), WithRelativeMotion(-5, 10), + WithToolType(ToolType::FINGER), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 5, POINTER_Y + 10)); @@ -252,24 +259,27 @@ TEST_F(GestureConverterTest, DragWithButton) { Gesture upGesture(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, upGesture); - 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 - 5, POINTER_Y + 10), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0), - WithCoords(POINTER_X - 5, POINTER_Y + 10), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithButtonState(0), - WithCoords(POINTER_X - 5, POINTER_Y + 10), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, upGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(0), + WithCoords(POINTER_X - 5, POINTER_Y + 10), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithButtonState(0), + WithCoords(POINTER_X - 5, POINTER_Y + 10), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithButtonState(0), + WithCoords(POINTER_X - 5, POINTER_Y + 10), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, Scroll) { @@ -279,50 +289,52 @@ TEST_F(GestureConverterTest, Scroll) { converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); - std::list<NotifyArgs> args = converter.handleGesture(downTime, READ_TIME, startGesture); - ASSERT_EQ(2u, args.size()); - - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y), - WithGestureScrollDistance(0, 0, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), WithDownTime(downTime), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithCoords(POINTER_X, POINTER_Y - 10), - WithGestureScrollDistance(0, 10, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(downTime, READ_TIME, ARBITRARY_TIME, startGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithCoords(POINTER_X, POINTER_Y), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification( + MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), WithDownTime(downTime), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithCoords(POINTER_X, POINTER_Y - 10), + WithGestureScrollDistance(0, 10, EPSILON), + WithMotionClassification( + MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); - ASSERT_EQ(1u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithCoords(POINTER_X, POINTER_Y - 15), - WithGestureScrollDistance(0, 5, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithCoords(POINTER_X, POINTER_Y - 15), + WithGestureScrollDistance(0, 5, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, GESTURES_FLING_START); - 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_UP), - WithCoords(POINTER_X, POINTER_Y - 15), - WithGestureScrollDistance(0, 0, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithCoords(POINTER_X, POINTER_Y - 15), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, Scroll_Rotated) { @@ -333,43 +345,47 @@ TEST_F(GestureConverterTest, Scroll_Rotated) { converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); - std::list<NotifyArgs> args = converter.handleGesture(downTime, READ_TIME, startGesture); - ASSERT_EQ(2u, args.size()); - - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y), - WithGestureScrollDistance(0, 0, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), WithDownTime(downTime), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithCoords(POINTER_X - 10, POINTER_Y), - WithGestureScrollDistance(0, 10, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(downTime, READ_TIME, ARBITRARY_TIME, startGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithCoords(POINTER_X, POINTER_Y), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification( + MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), WithDownTime(downTime), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithCoords(POINTER_X - 10, POINTER_Y), + WithGestureScrollDistance(0, 10, EPSILON), + WithMotionClassification( + MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); - ASSERT_EQ(1u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithCoords(POINTER_X - 15, POINTER_Y), - WithGestureScrollDistance(0, 5, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); - + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithCoords(POINTER_X - 15, POINTER_Y), + WithGestureScrollDistance(0, 5, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, GESTURES_FLING_START); - 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_UP), - WithCoords(POINTER_X - 15, POINTER_Y), - WithGestureScrollDistance(0, 0, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithCoords(POINTER_X - 15, POINTER_Y), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, Scroll_ClearsClassificationAfterGesture) { @@ -378,21 +394,22 @@ TEST_F(GestureConverterTest, Scroll_ClearsClassificationAfterGesture) { converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, GESTURES_FLING_START); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture); Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, moveGesture); - ASSERT_EQ(1u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionClassification(MotionClassification::NONE), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionClassification(MotionClassification::NONE), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, Scroll_ClearsScrollDistanceAfterGesture) { @@ -401,20 +418,21 @@ TEST_F(GestureConverterTest, Scroll_ClearsScrollDistanceAfterGesture) { converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, GESTURES_FLING_START); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture); // Move gestures don't use the fake finger array, so to test that gesture axes are cleared we // need to use another gesture type, like pinch. Gesture pinchGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_START); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, pinchGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, pinchGesture); ASSERT_FALSE(args.empty()); EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), WithGestureScrollDistance(0, 0, EPSILON)); } @@ -426,17 +444,19 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_ClearsClassificationAfterGesture) Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/0); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, liftGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/-5, /*dy=*/10); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, moveGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); ASSERT_EQ(1u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionClassification(MotionClassification::NONE)); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionClassification(MotionClassification::NONE)))); } TEST_F(GestureConverterTest, ThreeFingerSwipe_ClearsGestureAxesAfterGesture) { @@ -446,16 +466,17 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_ClearsGestureAxesAfterGesture) { Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/5, /*dy=*/5); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, liftGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); // Move gestures don't use the fake finger array, so to test that gesture axes are cleared we // need to use another gesture type, like pinch. Gesture pinchGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_START); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, pinchGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, pinchGesture); ASSERT_FALSE(args.empty()); EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), AllOf(WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(0))); @@ -472,7 +493,8 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 0, /* dy= */ 10); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); ASSERT_EQ(4u, args.size()); // Three fake fingers should be created. We don't actually care where they are, so long as they @@ -523,7 +545,7 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { Gesture continueGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 0, /* dy= */ 5); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); ASSERT_EQ(1u, args.size()); arg = std::get<NotifyMotionArgs>(args.front()); ASSERT_THAT(arg, @@ -540,30 +562,36 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { EXPECT_EQ(arg.pointerCoords[2].getY(), finger2Start.getY() - 15); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, liftGesture); - ASSERT_EQ(3u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(3), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(3), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), - WithGestureSwipeFingerCount(3), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(3), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(3u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(3), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(3), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, ThreeFingerSwipe_Rotated) { @@ -574,7 +602,8 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Rotated) { Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 0, /* dy= */ 10); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); ASSERT_EQ(4u, args.size()); // Three fake fingers should be created. We don't actually care where they are, so long as they @@ -616,7 +645,7 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Rotated) { Gesture continueGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 0, /* dy= */ 5); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); ASSERT_EQ(1u, args.size()); arg = std::get<NotifyMotionArgs>(args.front()); ASSERT_THAT(arg, @@ -631,23 +660,24 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Rotated) { EXPECT_EQ(arg.pointerCoords[2].getY(), finger2Start.getY()); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, liftGesture); - ASSERT_EQ(3u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithPointerCount(3u), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithPointerCount(2u), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), - WithPointerCount(1u), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), WithPointerCount(3u), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), WithPointerCount(2u), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithGestureOffset(0, 0, EPSILON), WithPointerCount(1u), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { @@ -657,7 +687,8 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { Gesture startGesture(kGestureFourFingerSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 10, /* dy= */ 0); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); ASSERT_EQ(5u, args.size()); // Four fake fingers should be created. We don't actually care where they are, so long as they @@ -720,7 +751,7 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { Gesture continueGesture(kGestureFourFingerSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 5, /* dy= */ 0); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); ASSERT_EQ(1u, args.size()); arg = std::get<NotifyMotionArgs>(args.front()); ASSERT_THAT(arg, @@ -739,38 +770,46 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { EXPECT_EQ(arg.pointerCoords[3].getY(), finger3Start.getY()); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, liftGesture); - ASSERT_EQ(4u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(4u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), - WithGestureSwipeFingerCount(4), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(4), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(4u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(4), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(3u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(4), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(4), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, Pinch_Inwards) { @@ -780,51 +819,57 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_START); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); - ASSERT_EQ(2u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), - WithCoords(POINTER_X - 100, POINTER_Y), WithPointerCount(1u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), - WithPointerCoords(1, POINTER_X + 100, POINTER_Y), WithPointerCount(2u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithCoords(POINTER_X - 100, POINTER_Y), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_DOWN | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCoords(1, POINTER_X + 100, POINTER_Y), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 0.8, GESTURES_ZOOM_UPDATE); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, updateGesture); - ASSERT_EQ(1u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(0.8f, EPSILON), - WithPointerCoords(0, POINTER_X - 80, POINTER_Y), - WithPointerCoords(1, POINTER_X + 80, POINTER_Y), WithPointerCount(2u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(0.8f, EPSILON), + WithPointerCoords(0, POINTER_X - 80, POINTER_Y), + WithPointerCoords(1, POINTER_X + 80, POINTER_Y), WithPointerCount(2u), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_END); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, endGesture); - ASSERT_EQ(2u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, Pinch_Outwards) { @@ -834,51 +879,57 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_START); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); - ASSERT_EQ(2u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), - WithCoords(POINTER_X - 100, POINTER_Y), WithPointerCount(1u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), - WithPointerCoords(1, POINTER_X + 100, POINTER_Y), WithPointerCount(2u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithCoords(POINTER_X - 100, POINTER_Y), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_DOWN | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCoords(1, POINTER_X + 100, POINTER_Y), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1.2, GESTURES_ZOOM_UPDATE); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, updateGesture); - ASSERT_EQ(1u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.2f, EPSILON), - WithPointerCoords(0, POINTER_X - 120, POINTER_Y), - WithPointerCoords(1, POINTER_X + 120, POINTER_Y), WithPointerCount(2u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.2f, EPSILON), + WithPointerCoords(0, POINTER_X - 120, POINTER_Y), + WithPointerCoords(1, POINTER_X + 120, POINTER_Y), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_END); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, endGesture); - ASSERT_EQ(2u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, Pinch_ClearsClassificationAfterGesture) { @@ -888,21 +939,22 @@ TEST_F(GestureConverterTest, Pinch_ClearsClassificationAfterGesture) { Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_START); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1.2, GESTURES_ZOOM_UPDATE); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, updateGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_END); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, endGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture); Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, moveGesture); - ASSERT_EQ(1u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionClassification(MotionClassification::NONE)); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionClassification(MotionClassification::NONE)))); } TEST_F(GestureConverterTest, Pinch_ClearsScaleFactorAfterGesture) { @@ -912,21 +964,22 @@ TEST_F(GestureConverterTest, Pinch_ClearsScaleFactorAfterGesture) { Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_START); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1.2, GESTURES_ZOOM_UPDATE); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, updateGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_END); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, endGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture); // Move gestures don't use the fake finger array, so to test that gesture axes are cleared we // need to use another gesture type, like scroll. Gesture scrollGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/1, /*dy=*/0); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, scrollGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, scrollGesture); ASSERT_FALSE(args.empty()); EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), WithGesturePinchScaleFactor(0, EPSILON)); } @@ -939,28 +992,28 @@ TEST_F(GestureConverterTest, ResetWithButtonPressed) { Gesture downGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*down=*/GESTURES_BUTTON_LEFT | GESTURES_BUTTON_RIGHT, /*up=*/GESTURES_BUTTON_NONE, /*is_tap=*/false); - (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, downGesture); + (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, downGesture); std::list<NotifyArgs> args = converter.reset(ARBITRARY_TIME); - ASSERT_EQ(3u, args.size()); - - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), - WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), - WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(0), - WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0), - WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), + WithCoords(POINTER_X, POINTER_Y), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), + WithButtonState(0), WithCoords(POINTER_X, POINTER_Y), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithButtonState(0), WithCoords(POINTER_X, POINTER_Y), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, ResetDuringScroll) { @@ -969,18 +1022,18 @@ TEST_F(GestureConverterTest, ResetDuringScroll) { converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); - (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); std::list<NotifyArgs> args = converter.reset(ARBITRARY_TIME); - ASSERT_EQ(1u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithCoords(POINTER_X, POINTER_Y - 10), - WithGestureScrollDistance(0, 0, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithCoords(POINTER_X, POINTER_Y - 10), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, ResetDuringThreeFingerSwipe) { @@ -990,31 +1043,35 @@ TEST_F(GestureConverterTest, ResetDuringThreeFingerSwipe) { Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/10); - (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); std::list<NotifyArgs> args = converter.reset(ARBITRARY_TIME); - ASSERT_EQ(3u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(3u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithGestureOffset(0, 0, EPSILON), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, ResetDuringPinch) { @@ -1024,22 +1081,24 @@ TEST_F(GestureConverterTest, ResetDuringPinch) { Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_START); - (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); std::list<NotifyArgs> args = converter.reset(ARBITRARY_TIME); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, FlingTapDown) { @@ -1049,7 +1108,8 @@ TEST_F(GestureConverterTest, FlingTapDown) { Gesture tapDownGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*vx=*/0.f, /*vy=*/0.f, GESTURES_FLING_TAP_DOWN); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, tapDownGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, tapDownGesture); ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), @@ -1069,52 +1129,57 @@ TEST_F(GestureConverterTest, Tap) { 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); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))))); 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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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), WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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), WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, tapGesture); + + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + 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), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + 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), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + 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), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithCoords(POINTER_X, POINTER_Y), + WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), + WithRelativeMotion(0, 0), WithToolType(ToolType::FINGER), + WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTest, Click) { @@ -1125,62 +1190,71 @@ TEST_F(GestureConverterTest, Click) { 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); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))))); 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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, buttonDownGesture); + + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + 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), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + 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), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); 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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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), WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, buttonUpGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + 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), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithCoords(POINTER_X, POINTER_Y), + WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), + WithRelativeMotion(0, 0), WithToolType(ToolType::FINGER), + WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F_WITH_FLAGS(GestureConverterTest, TapWithTapToClickDisabled, - REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) { + REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION), + REQUIRES_FLAGS_DISABLED(TOUCHPAD_PALM_REJECTION_V2)) { + nsecs_t currentTime = ARBITRARY_GESTURE_TIME; + // Tap should be ignored when disabled mReader->getContext()->setPreventingTouchpadTaps(true); @@ -1188,22 +1262,22 @@ TEST_F_WITH_FLAGS(GestureConverterTest, TapWithTapToClickDisabled, GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setDisplayId(ADISPLAY_ID_DEFAULT); - Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0, + Gesture flingGesture(kGestureFling, currentTime, currentTime, /* vx= */ 0, /* vy= */ 0, GESTURES_FLING_TAP_DOWN); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + std::list<NotifyArgs> args = + converter.handleGesture(currentTime, currentTime, currentTime, 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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))))); - Gesture tapGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, + Gesture tapGesture(kGestureButtonsChange, currentTime, currentTime, /* down= */ GESTURES_BUTTON_LEFT, /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, tapGesture); + args = converter.handleGesture(currentTime, currentTime, currentTime, tapGesture); // no events should be generated ASSERT_EQ(0u, args.size()); @@ -1212,18 +1286,21 @@ TEST_F_WITH_FLAGS(GestureConverterTest, TapWithTapToClickDisabled, ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); } -TEST_F_WITH_FLAGS(GestureConverterTest, ClickWithTapToClickDisabled, - REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) { - // Click should still produce button press/release events +TEST_F_WITH_FLAGS(GestureConverterTest, TapWithTapToClickDisabledWithDelay, + REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION_V2)) { + nsecs_t currentTime = ARBITRARY_GESTURE_TIME; + + // Tap should be ignored when disabled mReader->getContext()->setPreventingTouchpadTaps(true); InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setDisplayId(ADISPLAY_ID_DEFAULT); - Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0, + Gesture flingGesture(kGestureFling, currentTime, currentTime, /* vx= */ 0, /* vy= */ 0, GESTURES_FLING_TAP_DOWN); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + std::list<NotifyArgs> args = + converter.handleGesture(currentTime, currentTime, currentTime, flingGesture); ASSERT_EQ(1u, args.size()); ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), @@ -1232,49 +1309,143 @@ TEST_F_WITH_FLAGS(GestureConverterTest, ClickWithTapToClickDisabled, WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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()); + Gesture tapGesture(kGestureButtonsChange, currentTime, currentTime, + /* down= */ GESTURES_BUTTON_LEFT, + /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true); + args = converter.handleGesture(currentTime, currentTime, currentTime, tapGesture); + + // no events should be generated + ASSERT_EQ(0u, args.size()); + + // Future taps should be re-enabled + ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); + + // taps before the threshold should still be ignored + currentTime += TAP_ENABLE_DELAY_NANOS.count(); + flingGesture = Gesture(kGestureFling, currentTime, currentTime, /* vx= */ 0, + /* vy= */ 0, GESTURES_FLING_TAP_DOWN); + args = converter.handleGesture(currentTime, currentTime, currentTime, flingGesture); + ASSERT_EQ(1u, 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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithRelativeMotion(0, 0))); + + tapGesture = Gesture(kGestureButtonsChange, currentTime, currentTime, + /* down= */ GESTURES_BUTTON_LEFT, + /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true); + args = converter.handleGesture(currentTime, currentTime, currentTime, tapGesture); + + // no events should be generated + ASSERT_EQ(0u, args.size()); + + // taps after the threshold should be recognised + currentTime += 1; + flingGesture = Gesture(kGestureFling, currentTime, currentTime, /* vx= */ 0, + /* vy= */ 0, GESTURES_FLING_TAP_DOWN); + args = converter.handleGesture(currentTime, currentTime, currentTime, flingGesture); + + ASSERT_EQ(1u, args.size()); 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), WithDisplayId(ADISPLAY_ID_DEFAULT))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithRelativeMotion(0, 0))); - 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); + tapGesture = Gesture(kGestureButtonsChange, currentTime, currentTime, + /* down= */ GESTURES_BUTTON_LEFT, + /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true); + args = converter.handleGesture(currentTime, currentTime, currentTime, tapGesture); - ASSERT_EQ(3u, args.size()); + ASSERT_EQ(5u, args.size()); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithRelativeMotion(0.f, 0.f), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))); + args.pop_front(); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(1), + WithRelativeMotion(0.f, 0.f))); + 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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + WithRelativeMotion(0.f, 0.f))); 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), WithDisplayId(ADISPLAY_ID_DEFAULT))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithRelativeMotion(0.f, 0.f), + WithButtonState(0))); 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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithRelativeMotion(0, 0), + WithButtonState(0))); +} + +TEST_F_WITH_FLAGS(GestureConverterTest, ClickWithTapToClickDisabled, + REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) { + // Click should still produce button press/release events + mReader->getContext()->setPreventingTouchpadTaps(true); + + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); + + 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, ARBITRARY_TIME, flingGesture); + + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))))); + + 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, ARBITRARY_TIME, buttonDownGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + 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), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + 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), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); + + 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, ARBITRARY_TIME, buttonUpGesture); + + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + 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), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithCoords(POINTER_X, POINTER_Y), + WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(POINTER_X, POINTER_Y), + WithRelativeMotion(0, 0), WithToolType(ToolType::FINGER), + WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); // Future taps should be re-enabled ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); @@ -1290,14 +1461,14 @@ TEST_F_WITH_FLAGS(GestureConverterTest, MoveEnablesTapToClick, converter.setDisplayId(ADISPLAY_ID_DEFAULT); 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), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + 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), WithDisplayId(ADISPLAY_ID_DEFAULT))))); ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 5, POINTER_Y + 10)); @@ -1305,6 +1476,45 @@ TEST_F_WITH_FLAGS(GestureConverterTest, MoveEnablesTapToClick, ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); } +TEST_F_WITH_FLAGS(GestureConverterTest, KeypressCancelsHoverMove, + REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION_V2)) { + const nsecs_t gestureStartTime = 1000; + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); + + // Start a move gesture at gestureStartTime + Gesture moveGesture(kGestureMove, gestureStartTime, gestureStartTime, -5, 10); + std::list<NotifyArgs> args = + converter.handleGesture(gestureStartTime, READ_TIME, gestureStartTime, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE)))); + + // Key presses with IME connection should cancel ongoing move gesture + nsecs_t currentTime = gestureStartTime + 100; + mFakePolicy->setIsInputMethodConnectionActive(true); + mReader->getContext()->setLastKeyDownTimestamp(currentTime); + moveGesture = Gesture(kGestureMove, currentTime, currentTime, -5, 10); + args = converter.handleGesture(currentTime, READ_TIME, gestureStartTime, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)))); + + // any updates in existing move gesture should be ignored + moveGesture = Gesture(kGestureMove, currentTime, currentTime, -5, 10); + args = converter.handleGesture(currentTime, READ_TIME, gestureStartTime, moveGesture); + ASSERT_EQ(0u, args.size()); + + // New gesture should not be affected + currentTime += 100; + moveGesture = Gesture(kGestureMove, currentTime, currentTime, -5, 10); + args = converter.handleGesture(currentTime, READ_TIME, currentTime, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE)))); +} + // TODO(b/311416205): De-duplicate the test cases after the refactoring is complete and the flagging // logic can be removed. class GestureConverterTestWithChoreographer : public GestureConverterTestBase { @@ -1321,13 +1531,14 @@ TEST_F(GestureConverterTestWithChoreographer, Move) { converter.setDisplayId(ADISPLAY_ID_DEFAULT); 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(0, 0), - WithRelativeMotion(-5, 10), WithToolType(ToolType::FINGER), - WithButtonState(0), WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0), + WithRelativeMotion(-5, 10), WithToolType(ToolType::FINGER), + WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, Move_Rotated) { @@ -1337,13 +1548,14 @@ TEST_F(GestureConverterTestWithChoreographer, Move_Rotated) { converter.setDisplayId(ADISPLAY_ID_DEFAULT); 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(0, 0), - WithRelativeMotion(10, 5), WithToolType(ToolType::FINGER), WithButtonState(0), - WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0), + WithRelativeMotion(10, 5), WithToolType(ToolType::FINGER), + WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, ButtonsChange) { @@ -1355,65 +1567,64 @@ TEST_F(GestureConverterTestWithChoreographer, ButtonsChange) { Gesture downGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* down= */ GESTURES_BUTTON_LEFT | GESTURES_BUTTON_RIGHT, /* up= */ GESTURES_BUTTON_NONE, /* is_tap= */ false); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, downGesture); - ASSERT_EQ(3u, args.size()); - - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | - AMOTION_EVENT_BUTTON_SECONDARY), - WithCoords(0, 0), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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(0, 0), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), - WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | - AMOTION_EVENT_BUTTON_SECONDARY), - WithCoords(0, 0), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, downGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | + AMOTION_EVENT_BUTTON_SECONDARY), + WithCoords(0, 0), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithCoords(0, 0), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | + AMOTION_EVENT_BUTTON_SECONDARY), + WithCoords(0, 0), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); // Then release the left button Gesture leftUpGesture(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, leftUpGesture); - ASSERT_EQ(1u, args.size()); - - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), - WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), WithCoords(0, 0), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, leftUpGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), WithCoords(0, 0), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); // Finally release the right button Gesture rightUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* down= */ GESTURES_BUTTON_NONE, /* up= */ GESTURES_BUTTON_RIGHT, /* is_tap= */ false); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, rightUpGesture); - ASSERT_EQ(3u, args.size()); - - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(0), - WithCoords(0, 0), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0), - WithCoords(0, 0), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithButtonState(0), - WithCoords(0, 0), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, rightUpGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), + WithButtonState(0), WithCoords(0, 0), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithButtonState(0), WithCoords(0, 0), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithButtonState(0), WithCoords(0, 0), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, DragWithButton) { @@ -1425,53 +1636,53 @@ TEST_F(GestureConverterTestWithChoreographer, DragWithButton) { Gesture downGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* down= */ GESTURES_BUTTON_LEFT, /* up= */ GESTURES_BUTTON_NONE, /* is_tap= */ false); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, downGesture); - ASSERT_EQ(2u, args.size()); - - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithCoords(0, 0), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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(0, 0), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, downGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithCoords(0, 0), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithCoords(0, 0), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); // Move Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); - 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_MOVE), WithCoords(0, 0), - WithRelativeMotion(-5, 10), WithToolType(ToolType::FINGER), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(0, 0), + WithRelativeMotion(-5, 10), WithToolType(ToolType::FINGER), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); // Release the button Gesture upGesture(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, upGesture); - 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(0, 0), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0), - WithCoords(0, 0), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithButtonState(0), - WithCoords(0, 0), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, upGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(0), WithCoords(0, 0), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithButtonState(0), WithCoords(0, 0), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithButtonState(0), WithCoords(0, 0), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, Scroll) { @@ -1481,47 +1692,50 @@ TEST_F(GestureConverterTestWithChoreographer, Scroll) { converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); - std::list<NotifyArgs> args = converter.handleGesture(downTime, READ_TIME, startGesture); - ASSERT_EQ(2u, args.size()); - - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(0, 0), - WithGestureScrollDistance(0, 0, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), WithDownTime(downTime), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(0, -10), - WithGestureScrollDistance(0, 10, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(downTime, READ_TIME, ARBITRARY_TIME, startGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithCoords(0, 0), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification( + MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), WithDownTime(downTime), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithCoords(0, -10), + WithGestureScrollDistance(0, 10, EPSILON), + WithMotionClassification( + MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); - ASSERT_EQ(1u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(0, -15), - WithGestureScrollDistance(0, 5, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(0, -15), + WithGestureScrollDistance(0, 5, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, GESTURES_FLING_START); - 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_UP), WithCoords(0, 0 - 15), - WithGestureScrollDistance(0, 0, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithCoords(0, 0 - 15), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, Scroll_Rotated) { @@ -1532,40 +1746,46 @@ TEST_F(GestureConverterTestWithChoreographer, Scroll_Rotated) { converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); - std::list<NotifyArgs> args = converter.handleGesture(downTime, READ_TIME, startGesture); - ASSERT_EQ(2u, args.size()); - - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(0, 0), - WithGestureScrollDistance(0, 0, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), WithDownTime(downTime), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(-10, 0), - WithGestureScrollDistance(0, 10, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(downTime, READ_TIME, ARBITRARY_TIME, startGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithCoords(0, 0), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification( + MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), WithDownTime(downTime), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithCoords(-10, 0), + WithGestureScrollDistance(0, 10, EPSILON), + WithMotionClassification( + MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); - ASSERT_EQ(1u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(-15, 0), - WithGestureScrollDistance(0, 5, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(-15, 0), + WithGestureScrollDistance(0, 5, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, GESTURES_FLING_START); - 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_UP), WithCoords(-15, 0), - WithGestureScrollDistance(0, 0, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithCoords(-15, 0), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, Scroll_ClearsClassificationAfterGesture) { @@ -1574,21 +1794,22 @@ TEST_F(GestureConverterTestWithChoreographer, Scroll_ClearsClassificationAfterGe converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, GESTURES_FLING_START); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture); Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, moveGesture); - ASSERT_EQ(1u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionClassification(MotionClassification::NONE), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionClassification(MotionClassification::NONE), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, Scroll_ClearsScrollDistanceAfterGesture) { @@ -1597,20 +1818,21 @@ TEST_F(GestureConverterTestWithChoreographer, Scroll_ClearsScrollDistanceAfterGe converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, GESTURES_FLING_START); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture); // Move gestures don't use the fake finger array, so to test that gesture axes are cleared we // need to use another gesture type, like pinch. Gesture pinchGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_START); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, pinchGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, pinchGesture); ASSERT_FALSE(args.empty()); EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), WithGestureScrollDistance(0, 0, EPSILON)); } @@ -1622,17 +1844,18 @@ TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_ClearsClassificat Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/0); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, liftGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/-5, /*dy=*/10); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, moveGesture); - ASSERT_EQ(1u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionClassification(MotionClassification::NONE)); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionClassification(MotionClassification::NONE)))); } TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_ClearsGestureAxesAfterGesture) { @@ -1642,16 +1865,17 @@ TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_ClearsGestureAxes Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/5, /*dy=*/5); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, liftGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); // Move gestures don't use the fake finger array, so to test that gesture axes are cleared we // need to use another gesture type, like pinch. Gesture pinchGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_START); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, pinchGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, pinchGesture); ASSERT_FALSE(args.empty()); EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), AllOf(WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(0))); @@ -1668,7 +1892,8 @@ TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_Vertical) { Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 0, /* dy= */ 10); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); ASSERT_EQ(4u, args.size()); // Three fake fingers should be created. We don't actually care where they are, so long as they @@ -1719,7 +1944,7 @@ TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_Vertical) { Gesture continueGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 0, /* dy= */ 5); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); ASSERT_EQ(1u, args.size()); arg = std::get<NotifyMotionArgs>(args.front()); ASSERT_THAT(arg, @@ -1736,30 +1961,36 @@ TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_Vertical) { EXPECT_EQ(arg.pointerCoords[2].getY(), finger2Start.getY() - 15); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, liftGesture); - ASSERT_EQ(3u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(3), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(3), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), - WithGestureSwipeFingerCount(3), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(3), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(3u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(3), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(3), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_Rotated) { @@ -1770,7 +2001,8 @@ TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_Rotated) { Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 0, /* dy= */ 10); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); ASSERT_EQ(4u, args.size()); // Three fake fingers should be created. We don't actually care where they are, so long as they @@ -1812,7 +2044,7 @@ TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_Rotated) { Gesture continueGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 0, /* dy= */ 5); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); ASSERT_EQ(1u, args.size()); arg = std::get<NotifyMotionArgs>(args.front()); ASSERT_THAT(arg, @@ -1827,23 +2059,24 @@ TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_Rotated) { EXPECT_EQ(arg.pointerCoords[2].getY(), finger2Start.getY()); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, liftGesture); - ASSERT_EQ(3u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithPointerCount(3u), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithPointerCount(2u), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), - WithPointerCount(1u), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), WithPointerCount(3u), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), WithPointerCount(2u), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithGestureOffset(0, 0, EPSILON), WithPointerCount(1u), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, FourFingerSwipe_Horizontal) { @@ -1853,7 +2086,8 @@ TEST_F(GestureConverterTestWithChoreographer, FourFingerSwipe_Horizontal) { Gesture startGesture(kGestureFourFingerSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 10, /* dy= */ 0); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); ASSERT_EQ(5u, args.size()); // Four fake fingers should be created. We don't actually care where they are, so long as they @@ -1916,7 +2150,7 @@ TEST_F(GestureConverterTestWithChoreographer, FourFingerSwipe_Horizontal) { Gesture continueGesture(kGestureFourFingerSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 5, /* dy= */ 0); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); ASSERT_EQ(1u, args.size()); arg = std::get<NotifyMotionArgs>(args.front()); ASSERT_THAT(arg, @@ -1935,38 +2169,46 @@ TEST_F(GestureConverterTestWithChoreographer, FourFingerSwipe_Horizontal) { EXPECT_EQ(arg.pointerCoords[3].getY(), finger3Start.getY()); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, liftGesture); - ASSERT_EQ(4u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(4u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), - WithGestureSwipeFingerCount(4), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(4), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(4u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(4), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(3u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(4), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithGestureOffset(0, 0, EPSILON), + WithGestureSwipeFingerCount(4), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, Pinch_Inwards) { @@ -1976,50 +2218,56 @@ TEST_F(GestureConverterTestWithChoreographer, Pinch_Inwards) { Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_START); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); - ASSERT_EQ(2u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithCoords(-100, 0), - WithPointerCount(1u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCoords(1, 100, 0), - WithPointerCount(2u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithCoords(-100, 0), WithPointerCount(1u), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_DOWN | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCoords(1, 100, 0), WithPointerCount(2u), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 0.8, GESTURES_ZOOM_UPDATE); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, updateGesture); - ASSERT_EQ(1u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(0.8f, EPSILON), WithPointerCoords(0, -80, 0), - WithPointerCoords(1, 80, 0), WithPointerCount(2u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(0.8f, EPSILON), + WithPointerCoords(0, -80, 0), WithPointerCoords(1, 80, 0), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_END); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, endGesture); - ASSERT_EQ(2u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, Pinch_Outwards) { @@ -2029,50 +2277,56 @@ TEST_F(GestureConverterTestWithChoreographer, Pinch_Outwards) { Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_START); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); - ASSERT_EQ(2u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithCoords(-100, 0), - WithPointerCount(1u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCoords(1, 100, 0), - WithPointerCount(2u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithCoords(-100, 0), WithPointerCount(1u), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_DOWN | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCoords(1, 100, 0), WithPointerCount(2u), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1.1, GESTURES_ZOOM_UPDATE); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, updateGesture); - ASSERT_EQ(1u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.1f, EPSILON), WithPointerCoords(0, -110, 0), - WithPointerCoords(1, 110, 0), WithPointerCount(2u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.1f, EPSILON), + WithPointerCoords(0, -110, 0), WithPointerCoords(1, 110, 0), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_END); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, endGesture); - ASSERT_EQ(2u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, Pinch_ClearsClassificationAfterGesture) { @@ -2082,21 +2336,22 @@ TEST_F(GestureConverterTestWithChoreographer, Pinch_ClearsClassificationAfterGes Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_START); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1.2, GESTURES_ZOOM_UPDATE); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, updateGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_END); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, endGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture); Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, moveGesture); - ASSERT_EQ(1u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionClassification(MotionClassification::NONE)); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionClassification(MotionClassification::NONE)))); } TEST_F(GestureConverterTestWithChoreographer, Pinch_ClearsScaleFactorAfterGesture) { @@ -2106,21 +2361,22 @@ TEST_F(GestureConverterTestWithChoreographer, Pinch_ClearsScaleFactorAfterGestur Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_START); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1.2, GESTURES_ZOOM_UPDATE); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, updateGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_END); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, endGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture); // Move gestures don't use the fake finger array, so to test that gesture axes are cleared we // need to use another gesture type, like scroll. Gesture scrollGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/1, /*dy=*/0); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, scrollGesture); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, scrollGesture); ASSERT_FALSE(args.empty()); EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), WithGesturePinchScaleFactor(0, EPSILON)); } @@ -2133,27 +2389,27 @@ TEST_F(GestureConverterTestWithChoreographer, ResetWithButtonPressed) { Gesture downGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*down=*/GESTURES_BUTTON_LEFT | GESTURES_BUTTON_RIGHT, /*up=*/GESTURES_BUTTON_NONE, /*is_tap=*/false); - (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, downGesture); + (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, downGesture); std::list<NotifyArgs> args = converter.reset(ARBITRARY_TIME); - ASSERT_EQ(3u, args.size()); - - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), - WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), WithCoords(0, 0), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(0), - WithCoords(0, 0), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0), - WithCoords(0, 0), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), + WithCoords(0, 0), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), + WithButtonState(0), WithCoords(0, 0), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithButtonState(0), WithCoords(0, 0), + WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, ResetDuringScroll) { @@ -2162,17 +2418,17 @@ TEST_F(GestureConverterTestWithChoreographer, ResetDuringScroll) { converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); - (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); std::list<NotifyArgs> args = converter.reset(ARBITRARY_TIME); - ASSERT_EQ(1u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithCoords(0, -10), - WithGestureScrollDistance(0, 0, EPSILON), - WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithCoords(0, -10), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(ToolType::FINGER), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, ResetDuringThreeFingerSwipe) { @@ -2182,31 +2438,35 @@ TEST_F(GestureConverterTestWithChoreographer, ResetDuringThreeFingerSwipe) { Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/10); - (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); std::list<NotifyArgs> args = converter.reset(ARBITRARY_TIME); - ASSERT_EQ(3u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), - WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(ToolType::FINGER), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(3u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithGestureOffset(0, 0, EPSILON), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithGestureOffset(0, 0, EPSILON), + WithMotionClassification( + MotionClassification::MULTI_FINGER_SWIPE), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, ResetDuringPinch) { @@ -2216,22 +2476,24 @@ TEST_F(GestureConverterTestWithChoreographer, ResetDuringPinch) { Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_START); - (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); std::list<NotifyArgs> args = converter.reset(ARBITRARY_TIME); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithMotionClassification(MotionClassification::PINCH), - WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), - WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, FlingTapDown) { @@ -2241,7 +2503,8 @@ TEST_F(GestureConverterTestWithChoreographer, FlingTapDown) { Gesture tapDownGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*vx=*/0.f, /*vy=*/0.f, GESTURES_FLING_TAP_DOWN); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, tapDownGesture); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, tapDownGesture); ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0), @@ -2257,50 +2520,54 @@ TEST_F(GestureConverterTestWithChoreographer, Tap) { 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); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture); - ASSERT_EQ(1u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0), - WithRelativeMotion(0, 0), WithToolType(ToolType::FINGER), WithButtonState(0), - WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0), + WithRelativeMotion(0, 0), WithToolType(ToolType::FINGER), + WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); 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(0, 0), - WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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(0, 0), - WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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(0, 0), WithRelativeMotion(0.f, 0.f), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(1.0f), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithCoords(0, 0), - WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(0), WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0), - WithRelativeMotion(0, 0), WithToolType(ToolType::FINGER), WithButtonState(0), - WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, tapGesture); + + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithCoords(0, 0), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithPressure(1.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithCoords(0, 0), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithPressure(1.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(0), WithCoords(0, 0), + WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(1.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithCoords(0, 0), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(0, 0), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F(GestureConverterTestWithChoreographer, Click) { @@ -2311,7 +2578,8 @@ TEST_F(GestureConverterTestWithChoreographer, Click) { 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); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture); ASSERT_EQ(1u, args.size()); ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), @@ -2322,49 +2590,56 @@ TEST_F(GestureConverterTestWithChoreographer, Click) { 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(0, 0), - WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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(0, 0), - WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, buttonDownGesture); + + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithCoords(0, 0), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithPressure(1.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithCoords(0, 0), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithPressure(1.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); 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(0, 0), WithRelativeMotion(0.f, 0.f), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(1.0f), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithCoords(0, 0), - WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(0), WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0), - WithRelativeMotion(0, 0), WithToolType(ToolType::FINGER), WithButtonState(0), - WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, buttonUpGesture); + + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(0), WithCoords(0, 0), + WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(1.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithCoords(0, 0), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(0, 0), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); } TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, TapWithTapToClickDisabled, - REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) { + REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION), + REQUIRES_FLAGS_DISABLED(TOUCHPAD_PALM_REJECTION_V2)) { + nsecs_t currentTime = ARBITRARY_GESTURE_TIME; + // Tap should be ignored when disabled mReader->getContext()->setPreventingTouchpadTaps(true); @@ -2372,21 +2647,22 @@ TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, TapWithTapToClickDisabl GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setDisplayId(ADISPLAY_ID_DEFAULT); - Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0, + Gesture flingGesture(kGestureFling, currentTime, currentTime, /* vx= */ 0, /* vy= */ 0, GESTURES_FLING_TAP_DOWN); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + std::list<NotifyArgs> args = + converter.handleGesture(currentTime, currentTime, currentTime, flingGesture); - ASSERT_EQ(1u, args.size()); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0), - WithRelativeMotion(0, 0), WithToolType(ToolType::FINGER), WithButtonState(0), - WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0), + WithRelativeMotion(0, 0), WithToolType(ToolType::FINGER), + WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); - Gesture tapGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, + Gesture tapGesture(kGestureButtonsChange, currentTime, currentTime, /* down= */ GESTURES_BUTTON_LEFT, /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true); - args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, tapGesture); + args = converter.handleGesture(currentTime, currentTime, currentTime, tapGesture); // no events should be generated ASSERT_EQ(0u, args.size()); @@ -2395,18 +2671,21 @@ TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, TapWithTapToClickDisabl ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); } -TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, ClickWithTapToClickDisabled, - REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) { - // Click should still produce button press/release events +TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, TapWithTapToClickDisabledWithDelay, + REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION_V2)) { + nsecs_t currentTime = ARBITRARY_GESTURE_TIME; + + // Tap should be ignored when disabled mReader->getContext()->setPreventingTouchpadTaps(true); InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setDisplayId(ADISPLAY_ID_DEFAULT); - Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0, + Gesture flingGesture(kGestureFling, currentTime, currentTime, /* vx= */ 0, /* vy= */ 0, GESTURES_FLING_TAP_DOWN); - std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + std::list<NotifyArgs> args = + converter.handleGesture(currentTime, currentTime, currentTime, flingGesture); ASSERT_EQ(1u, args.size()); ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), @@ -2414,48 +2693,141 @@ TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, ClickWithTapToClickDisa WithRelativeMotion(0, 0), WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); - 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()); + Gesture tapGesture(kGestureButtonsChange, currentTime, currentTime, + /* down= */ GESTURES_BUTTON_LEFT, + /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true); + args = converter.handleGesture(currentTime, currentTime, currentTime, tapGesture); + + // no events should be generated + ASSERT_EQ(0u, args.size()); + // Future taps should be re-enabled + ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); + + // taps before the threshold should still be ignored + currentTime += TAP_ENABLE_DELAY_NANOS.count(); + flingGesture = Gesture(kGestureFling, currentTime, currentTime, /* vx= */ 0, + /* vy= */ 0, GESTURES_FLING_TAP_DOWN); + args = converter.handleGesture(currentTime, currentTime, currentTime, flingGesture); + + ASSERT_EQ(1u, args.size()); ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(0, 0), - WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f), - WithDisplayId(ADISPLAY_ID_DEFAULT))); - args.pop_front(); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithRelativeMotion(0, 0))); + + tapGesture = Gesture(kGestureButtonsChange, currentTime, currentTime, + /* down= */ GESTURES_BUTTON_LEFT, + /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true); + args = converter.handleGesture(currentTime, currentTime, currentTime, tapGesture); + + // no events should be generated + ASSERT_EQ(0u, args.size()); + + // taps after the threshold should be recognised + currentTime += 1; + flingGesture = Gesture(kGestureFling, currentTime, currentTime, /* vx= */ 0, + /* vy= */ 0, GESTURES_FLING_TAP_DOWN); + args = converter.handleGesture(currentTime, currentTime, currentTime, flingGesture); + + ASSERT_EQ(1u, args.size()); 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(0, 0), - WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithRelativeMotion(0, 0))); - 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); + tapGesture = Gesture(kGestureButtonsChange, currentTime, currentTime, + /* down= */ GESTURES_BUTTON_LEFT, + /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true); + args = converter.handleGesture(currentTime, currentTime, currentTime, tapGesture); - ASSERT_EQ(3u, args.size()); + ASSERT_EQ(5u, args.size()); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithRelativeMotion(0.f, 0.f), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))); + args.pop_front(); + ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(1), + WithRelativeMotion(0.f, 0.f))); + 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(0, 0), WithRelativeMotion(0.f, 0.f), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(1.0f), - WithDisplayId(ADISPLAY_ID_DEFAULT))); + WithRelativeMotion(0.f, 0.f))); args.pop_front(); ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithCoords(0, 0), - WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(0), WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithRelativeMotion(0.f, 0.f), + WithButtonState(0))); args.pop_front(); ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0), - WithRelativeMotion(0, 0), WithToolType(ToolType::FINGER), WithButtonState(0), - WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithRelativeMotion(0, 0), + WithButtonState(0))); +} + +TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, ClickWithTapToClickDisabled, + REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) { + // Click should still produce button press/release events + mReader->getContext()->setPreventingTouchpadTaps(true); + + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); + + 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, ARBITRARY_TIME, flingGesture); + + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0), + WithRelativeMotion(0, 0), WithToolType(ToolType::FINGER), + WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); + + 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, ARBITRARY_TIME, buttonDownGesture); + + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithCoords(0, 0), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithPressure(1.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithCoords(0, 0), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithPressure(1.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); + + 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, ARBITRARY_TIME, buttonUpGesture); + + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(0), WithCoords(0, 0), + WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(1.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithCoords(0, 0), WithRelativeMotion(0.f, 0.f), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + WithCoords(0, 0), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER), WithButtonState(0), + WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); // Future taps should be re-enabled ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); @@ -2471,16 +2843,57 @@ TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, MoveEnablesTapToClick, converter.setDisplayId(ADISPLAY_ID_DEFAULT); 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()); + std::list<NotifyArgs> args = + converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); - ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0), - WithRelativeMotion(-5, 10), WithToolType(ToolType::FINGER), - WithButtonState(0), WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0), + WithRelativeMotion(-5, 10), WithToolType(ToolType::FINGER), + WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))))); // Future taps should be re-enabled ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); } +TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, KeypressCancelsHoverMove, + REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION_V2)) { + const nsecs_t gestureStartTime = 1000; + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); + + // Start a move gesture at gestureStartTime + Gesture moveGesture(kGestureMove, gestureStartTime, gestureStartTime, -5, 10); + std::list<NotifyArgs> args = + converter.handleGesture(gestureStartTime, READ_TIME, gestureStartTime, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE)))); + + // Key presses with IME connection should cancel ongoing move gesture + nsecs_t currentTime = gestureStartTime + 100; + mFakePolicy->setIsInputMethodConnectionActive(true); + mReader->getContext()->setLastKeyDownTimestamp(currentTime); + moveGesture = Gesture(kGestureMove, currentTime, currentTime, -5, 10); + args = converter.handleGesture(currentTime, READ_TIME, gestureStartTime, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)))); + + // any updates in existing move gesture should be ignored + moveGesture = Gesture(kGestureMove, currentTime, currentTime, -5, 10); + args = converter.handleGesture(currentTime, READ_TIME, gestureStartTime, moveGesture); + ASSERT_EQ(0u, args.size()); + + // New gesture should not be affected + currentTime += 100; + moveGesture = Gesture(kGestureMove, currentTime, currentTime, -5, 10); + args = converter.handleGesture(currentTime, READ_TIME, currentTime, moveGesture); + ASSERT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE)))); +} + } // namespace android diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 5002391f61..a880a4c6bd 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -549,7 +549,7 @@ private: } } - void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) override {} + void interceptMotionBeforeQueueing(int32_t, uint32_t, int32_t, nsecs_t, uint32_t&) override {} nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent&, uint32_t) override { nsecs_t delay = std::chrono::nanoseconds(mInterceptKeyTimeout).count(); @@ -572,7 +572,8 @@ private: /** We simply reconstruct NotifySwitchArgs in policy because InputDispatcher is * essentially a passthrough for notifySwitch. */ - mLastNotifySwitch = NotifySwitchArgs(/*id=*/1, when, policyFlags, switchValues, switchMask); + mLastNotifySwitch = + NotifySwitchArgs(InputEvent::nextId(), when, policyFlags, switchValues, switchMask); } void pokeUserActivity(nsecs_t, int32_t, int32_t) override { @@ -836,7 +837,8 @@ TEST_F(InputDispatcherTest, NotifyConfigurationChanged_CallsPolicy) { } TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) { - NotifySwitchArgs args(/*id=*/10, /*eventTime=*/20, /*policyFlags=*/0, /*switchValues=*/1, + NotifySwitchArgs args(InputEvent::nextId(), /*eventTime=*/20, /*policyFlags=*/0, + /*switchValues=*/1, /*switchMask=*/2); mDispatcher->notifySwitch(args); @@ -1182,6 +1184,11 @@ public: mInfo.setInputConfig(WindowInfo::InputConfig::DISABLE_USER_ACTIVITY, disableUserActivity); } + void setGlobalStylusBlocksTouch(bool shouldGlobalStylusBlockTouch) { + mInfo.setInputConfig(WindowInfo::InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH, + shouldGlobalStylusBlockTouch); + } + void setAlpha(float alpha) { mInfo.alpha = alpha; } void setTouchOcclusionMode(TouchOcclusionMode mode) { mInfo.touchOcclusionMode = mode; } @@ -1221,31 +1228,27 @@ public: void setWindowOffset(float offsetX, float offsetY) { mInfo.transform.set(offsetX, offsetY); } - KeyEvent* consumeKey(bool handled = true) { - InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED, handled); - if (event == nullptr) { - ADD_FAILURE() << "Consume failed : no event"; - return nullptr; + const KeyEvent& consumeKey(bool handled = true) { + const InputEvent& event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED, handled); + if (event.getType() != InputEventType::KEY) { + LOG(FATAL) << "Instead of key event, got " << event; } - if (event->getType() != InputEventType::KEY) { - ADD_FAILURE() << "Instead of key event, got " << *event; - return nullptr; - } - return static_cast<KeyEvent*>(event); + return static_cast<const 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); + const KeyEvent& keyEvent = consumeKey(); + ASSERT_THAT(keyEvent, matcher); } void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) { - consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId, expectedFlags); + consumeKeyEvent(AllOf(WithKeyAction(ACTION_DOWN), WithDisplayId(expectedDisplayId), + WithFlags(expectedFlags))); } void consumeKeyUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) { - consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_UP, expectedDisplayId, expectedFlags); + consumeKeyEvent(AllOf(WithKeyAction(ACTION_UP), WithDisplayId(expectedDisplayId), + WithFlags(expectedFlags))); } void consumeMotionCancel(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, @@ -1267,44 +1270,46 @@ public: void consumeAnyMotionDown(std::optional<int32_t> expectedDisplayId = std::nullopt, std::optional<int32_t> expectedFlags = std::nullopt) { - consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN, expectedDisplayId, - expectedFlags); + consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), + testing::Conditional(expectedDisplayId.has_value(), + WithDisplayId(*expectedDisplayId), testing::_), + testing::Conditional(expectedFlags.has_value(), WithFlags(*expectedFlags), + testing::_))); } void consumeMotionPointerDown(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { - int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN | + const int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); - consumeEvent(InputEventType::MOTION, action, expectedDisplayId, expectedFlags); + consumeMotionEvent(AllOf(WithMotionAction(action), WithDisplayId(expectedDisplayId), + WithFlags(expectedFlags))); } void consumeMotionPointerUp(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { - int32_t action = AMOTION_EVENT_ACTION_POINTER_UP | + const int32_t action = AMOTION_EVENT_ACTION_POINTER_UP | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); - consumeEvent(InputEventType::MOTION, action, expectedDisplayId, expectedFlags); + consumeMotionEvent(AllOf(WithMotionAction(action), WithDisplayId(expectedDisplayId), + WithFlags(expectedFlags))); } void consumeMotionUp(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { - consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP, expectedDisplayId, - expectedFlags); + consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDisplayId(expectedDisplayId), + WithFlags(expectedFlags))); } void consumeMotionOutside(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { - consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_OUTSIDE, expectedDisplayId, - expectedFlags); + consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_OUTSIDE), + WithDisplayId(expectedDisplayId), WithFlags(expectedFlags))); } - void consumeMotionOutsideWithZeroedCoords(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, - int32_t expectedFlags = 0) { - 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 consumeMotionOutsideWithZeroedCoords() { + consumeMotionEvent( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_OUTSIDE), WithRawCoords(0, 0))); } void consumeFocusEvent(bool hasFocus, bool inTouchMode = true) { @@ -1319,21 +1324,15 @@ public: mInputReceiver->consumeCaptureEvent(hasCapture); } - const MotionEvent& consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) { - MotionEvent* motionEvent = consumeMotion(); - if (nullptr == motionEvent) { - LOG(FATAL) << "Did not get a motion event, but expected " << matcher; + const MotionEvent& consumeMotionEvent( + const ::testing::Matcher<MotionEvent>& matcher = testing::_) { + const InputEvent& event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); + if (event.getType() != InputEventType::MOTION) { + LOG(FATAL) << "Instead of motion event, got " << event; } - EXPECT_THAT(*motionEvent, matcher); - return *motionEvent; - } - - void consumeEvent(InputEventType expectedEventType, int32_t expectedAction, - std::optional<int32_t> expectedDisplayId, - std::optional<int32_t> expectedFlags) { - ASSERT_NE(mInputReceiver, nullptr) << "Invalid consume event on window with no receiver"; - mInputReceiver->consumeEvent(expectedEventType, expectedAction, expectedDisplayId, - expectedFlags); + const auto& motionEvent = static_cast<const MotionEvent&>(event); + EXPECT_THAT(motionEvent, matcher); + return motionEvent; } void consumeDragEvent(bool isExiting, float x, float y) { @@ -1364,26 +1363,6 @@ public: mInputReceiver->sendTimeline(inputEventId, timeline); } - InputEvent* consume(std::chrono::milliseconds timeout, bool handled = true) { - if (mInputReceiver == nullptr) { - return nullptr; - } - return mInputReceiver->consume(timeout, handled); - } - - MotionEvent* consumeMotion() { - InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); - if (event == nullptr) { - ADD_FAILURE() << "Consume failed : no event"; - return nullptr; - } - if (event->getType() != InputEventType::MOTION) { - ADD_FAILURE() << "Instead of motion event, got " << *event; - return nullptr; - } - return static_cast<MotionEvent*>(event); - } - void assertNoEvents() { if (mInputReceiver == nullptr && mInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) { @@ -1415,6 +1394,17 @@ private: std::shared_ptr<FakeInputReceiver> mInputReceiver; static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger friend class sp<FakeWindowHandle>; + + const InputEvent& consume(std::chrono::milliseconds timeout, bool handled = true) { + if (mInputReceiver == nullptr) { + LOG(FATAL) << "Cannot consume event from a window with no input event receiver"; + } + InputEvent* event = mInputReceiver->consume(timeout, handled); + if (event == nullptr) { + LOG(FATAL) << "Consume failed: no event"; + } + return *event; + } }; std::atomic<int32_t> FakeWindowHandle::sId{1}; @@ -1579,9 +1569,9 @@ static InputEventInjectionResult injectMotionUp(InputDispatcher& dispatcher, int static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) { nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid key event. - NotifyKeyArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, AINPUT_SOURCE_KEYBOARD, - displayId, POLICY_FLAG_PASS_TO_USER, action, /*flags=*/0, AKEYCODE_A, KEY_A, - AMETA_NONE, currentTime); + NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, + AINPUT_SOURCE_KEYBOARD, displayId, POLICY_FLAG_PASS_TO_USER, action, + /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, currentTime); return args; } @@ -1590,9 +1580,9 @@ static NotifyKeyArgs generateSystemShortcutArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) { nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid key event. - NotifyKeyArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, AINPUT_SOURCE_KEYBOARD, - displayId, 0, action, /*flags=*/0, AKEYCODE_C, KEY_C, AMETA_META_ON, - currentTime); + NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, + AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_C, KEY_C, + AMETA_META_ON, currentTime); return args; } @@ -1601,9 +1591,9 @@ static NotifyKeyArgs generateAssistantKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) { nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid key event. - NotifyKeyArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, AINPUT_SOURCE_KEYBOARD, - displayId, 0, action, /*flags=*/0, AKEYCODE_ASSIST, KEY_ASSISTANT, - AMETA_NONE, currentTime); + NotifyKeyArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, + AINPUT_SOURCE_KEYBOARD, displayId, 0, action, /*flags=*/0, AKEYCODE_ASSIST, + KEY_ASSISTANT, AMETA_NONE, currentTime); return args; } @@ -1631,9 +1621,9 @@ static NotifyKeyArgs generateAssistantKeyArgs(int32_t action, nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid motion event. - NotifyMotionArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, source, displayId, - POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0, /*flags=*/0, - AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE, + NotifyMotionArgs args(InputEvent::nextId(), currentTime, /*readTime=*/0, DEVICE_ID, source, + displayId, POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0, + /*flags=*/0, AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties, pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0, AMOTION_EVENT_INVALID_CURSOR_POSITION, @@ -1652,7 +1642,8 @@ static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32 static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs( const PointerCaptureRequest& request) { - return NotifyPointerCaptureChangedArgs(/*id=*/0, systemTime(SYSTEM_TIME_MONOTONIC), request); + return NotifyPointerCaptureChangedArgs(InputEvent::nextId(), systemTime(SYSTEM_TIME_MONOTONIC), + request); } } // namespace @@ -3355,6 +3346,150 @@ TEST_F(InputDispatcherMultiDeviceTest, StylusHoverIgnoresTouchTap) { } /** + * If stylus is down anywhere on the screen, then touches should not be delivered to windows that + * have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH. + * + * Two windows: one on the left and one on the right. + * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config. + * Stylus down on the left window, and then touch down on the right window. + * Check that the right window doesn't get touches while the stylus is down on the left window. + */ +TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusDownBlocksTouch) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> leftWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Left window", + ADISPLAY_ID_DEFAULT); + leftWindow->setFrame(Rect(0, 0, 100, 100)); + + sp<FakeWindowHandle> sbtRightWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, + "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT); + sbtRightWindow->setFrame(Rect(100, 100, 200, 200)); + sbtRightWindow->setGlobalStylusBlocksTouch(true); + + mDispatcher->onWindowInfosChanged( + {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0}); + + const int32_t stylusDeviceId = 5; + const int32_t touchDeviceId = 4; + + // Stylus down in the left window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52)) + .deviceId(stylusDeviceId) + .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); + + // Finger tap on the right window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151)) + .deviceId(touchDeviceId) + .build()); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151)) + .deviceId(touchDeviceId) + .build()); + + // The touch should be blocked, because stylus is down somewhere else on screen! + sbtRightWindow->assertNoEvents(); + + // Continue stylus motion, and ensure it's not impacted. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53)) + .deviceId(stylusDeviceId) + .build()); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53)) + .deviceId(stylusDeviceId) + .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId))); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_UP), WithDeviceId(stylusDeviceId))); + + // Now that the stylus gesture is done, touches should be getting delivered correctly. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153)) + .deviceId(touchDeviceId) + .build()); + sbtRightWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); +} + +/** + * If stylus is hovering anywhere on the screen, then touches should not be delivered to windows + * that have InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH. + * + * Two windows: one on the left and one on the right. + * The window on the right has GLOBAL_STYLUS_BLOCKS_TOUCH config. + * Stylus hover on the left window, and then touch down on the right window. + * Check that the right window doesn't get touches while the stylus is hovering on the left window. + */ +TEST_F(InputDispatcherMultiDeviceTest, GlobalStylusHoverBlocksTouch) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> leftWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Left window", + ADISPLAY_ID_DEFAULT); + leftWindow->setFrame(Rect(0, 0, 100, 100)); + + sp<FakeWindowHandle> sbtRightWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, + "Stylus blocks touch (right) window", ADISPLAY_ID_DEFAULT); + sbtRightWindow->setFrame(Rect(100, 100, 200, 200)); + sbtRightWindow->setGlobalStylusBlocksTouch(true); + + mDispatcher->onWindowInfosChanged( + {{*leftWindow->getInfo(), *sbtRightWindow->getInfo()}, {}, 0, 0}); + + const int32_t stylusDeviceId = 5; + const int32_t touchDeviceId = 4; + + // Stylus hover in the left window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(52)) + .deviceId(stylusDeviceId) + .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); + + // Finger tap on the right window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151)) + .deviceId(touchDeviceId) + .build()); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(151)) + .deviceId(touchDeviceId) + .build()); + + // The touch should be blocked, because stylus is hovering somewhere else on screen! + sbtRightWindow->assertNoEvents(); + + // Continue stylus motion, and ensure it's not impacted. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53)) + .deviceId(stylusDeviceId) + .build()); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(53)) + .deviceId(stylusDeviceId) + .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId))); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId))); + + // Now that the stylus gesture is done, touches should be getting delivered correctly. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(153)) + .deviceId(touchDeviceId) + .build()); + sbtRightWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); +} + +/** * A spy window above a window with no input channel. * Start hovering with a stylus device, and then tap with it. * Ensure spy window receives the entire sequence. @@ -3625,20 +3760,18 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) { mDispatcher->waitForIdle(); - MotionEvent* motionEvent1 = window1->consumeMotion(); - ASSERT_NE(motionEvent1, nullptr); + const MotionEvent& motionEvent1 = window1->consumeMotionEvent(); window2->assertNoEvents(); - 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(); - MotionEvent* motionEvent2 = window2->consumeMotion(); - ASSERT_NE(motionEvent2, nullptr); - nsecs_t downTimeForWindow2 = motionEvent2->getDownTime(); + const MotionEvent& motionEvent2 = window2->consumeMotionEvent(); + 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}})); @@ -4233,8 +4366,7 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) { // When device reset happens, that key stream should be terminated with FLAG_CANCELED // on the app side. mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID}); - window->consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT, - AKEY_EVENT_FLAG_CANCELED); + window->consumeKeyUp(ADISPLAY_ID_DEFAULT, AKEY_EVENT_FLAG_CANCELED); } TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) { @@ -4473,12 +4605,12 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - const MotionEvent* event = window->consumeMotion(); - EXPECT_EQ(POINTER_1_DOWN, event->getAction()); - EXPECT_EQ(70, event->getX(0)); // 50 + 20 - EXPECT_EQ(90, event->getY(0)); // 50 + 40 - EXPECT_EQ(-10, event->getX(1)); // -30 + 20 - EXPECT_EQ(-10, event->getY(1)); // -50 + 40 + const MotionEvent& event = window->consumeMotionEvent(); + EXPECT_EQ(POINTER_1_DOWN, event.getAction()); + EXPECT_EQ(70, event.getX(0)); // 50 + 20 + EXPECT_EQ(90, event.getY(0)); // 50 + 40 + EXPECT_EQ(-10, event.getX(1)); // -30 + 20 + EXPECT_EQ(-10, event.getY(1)); // -50 + 40 } /** @@ -4744,15 +4876,15 @@ TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTarg EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken())); // windowDefaultDisplay gets cancel - MotionEvent* event = windowDefaultDisplay->consumeMotion(); - EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction()); + const MotionEvent& event = windowDefaultDisplay->consumeMotionEvent(); + EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event.getAction()); // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of // SECOND_DISPLAY_ID, the x and y coordinates are 200 - EXPECT_EQ(100, event->getX(0)); - EXPECT_EQ(100, event->getY(0)); + EXPECT_EQ(100, event.getX(0)); + EXPECT_EQ(100, event.getY(0)); } /** @@ -4882,19 +5014,18 @@ TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinate {PointF{150, 220}})); firstWindow->assertNoEvents(); - const MotionEvent* event = secondWindow->consumeMotion(); - ASSERT_NE(nullptr, event); - EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction()); + const MotionEvent& event = secondWindow->consumeMotionEvent(); + EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event.getAction()); // Ensure that the events from the "getRaw" API are in logical display coordinates. - EXPECT_EQ(300, event->getRawX(0)); - EXPECT_EQ(880, event->getRawY(0)); + EXPECT_EQ(300, event.getRawX(0)); + EXPECT_EQ(880, event.getRawY(0)); // Ensure that the x and y values are in the window's coordinate space. // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in // the logical display space. This will be the origin of the window space. - EXPECT_EQ(100, event->getX(0)); - EXPECT_EQ(80, event->getY(0)); + EXPECT_EQ(100, event.getX(0)); + EXPECT_EQ(80, event.getY(0)); } TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) { @@ -5968,8 +6099,7 @@ TEST_F(InputDispatcherTest, TestMoveEvent) { motionArgs.pointerCoords[0].getX() - 10); mDispatcher->notifyMotion(motionArgs); - window->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE, ADISPLAY_ID_DEFAULT, - /*expectedFlags=*/0); + window->consumeMotionMove(ADISPLAY_ID_DEFAULT, /*expectedFlags=*/0); } /** @@ -6039,10 +6169,9 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN); mDispatcher->notifyKey(keyArgs); - KeyEvent* event = window->consumeKey(); - ASSERT_NE(event, nullptr); + const KeyEvent& event = window->consumeKey(); - std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event); + std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(event); ASSERT_NE(verified, nullptr); ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY); @@ -6083,10 +6212,9 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(motionArgs); - MotionEvent* event = window->consumeMotion(); - ASSERT_NE(event, nullptr); + const MotionEvent& event = window->consumeMotionEvent(); - std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event); + std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(event); ASSERT_NE(verified, nullptr); ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION); @@ -6664,9 +6792,8 @@ protected: } void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) { - KeyEvent* event = mWindow->consumeKey(handled); - ASSERT_NE(event, nullptr) << "Did not receive key event"; - ASSERT_THAT(*event, matcher); + const KeyEvent& event = mWindow->consumeKey(handled); + ASSERT_THAT(event, matcher); } }; @@ -6897,7 +7024,7 @@ protected: mDispatcher->notifyKey(keyArgs); // Window should receive key down event. - mWindow->consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT, + mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT, /*expectedFlags=*/0); } }; @@ -6967,10 +7094,9 @@ TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFrom GTEST_SKIP() << "Flaky test (b/270393106)"; sendAndConsumeKeyDown(/*deviceId=*/1); for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { - KeyEvent* repeatEvent = mWindow->consumeKey(); - ASSERT_NE(nullptr, repeatEvent) << "Didn't receive event with repeat count " << repeatCount; + const KeyEvent& repeatEvent = mWindow->consumeKey(); EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER, - IdGenerator::getSource(repeatEvent->getId())); + IdGenerator::getSource(repeatEvent.getId())); } } @@ -6980,9 +7106,8 @@ TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEvent std::unordered_set<int32_t> idSet; for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { - KeyEvent* repeatEvent = mWindow->consumeKey(); - ASSERT_NE(nullptr, repeatEvent) << "Didn't receive event with repeat count " << repeatCount; - int32_t id = repeatEvent->getId(); + const KeyEvent& repeatEvent = mWindow->consumeKey(); + int32_t id = repeatEvent.getId(); EXPECT_EQ(idSet.end(), idSet.find(id)); idSet.insert(id); } @@ -7071,8 +7196,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0}); // Old focus should receive a cancel event. - windowInSecondary->consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_UP, ADISPLAY_ID_NONE, - AKEY_EVENT_FLAG_CANCELED); + windowInSecondary->consumeKeyUp(ADISPLAY_ID_NONE, AKEY_EVENT_FLAG_CANCELED); // Test inject a key down, should timeout because of no target window. ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher)); @@ -7550,24 +7674,21 @@ protected: void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction, const std::vector<PointF>& points) { const std::string name = window->getName(); - MotionEvent* motionEvent = window->consumeMotion(); - - ASSERT_NE(nullptr, motionEvent) - << name.c_str() << ": consumer should have returned non-NULL event."; + const MotionEvent& motionEvent = + window->consumeMotionEvent(WithMotionAction(expectedAction)); - ASSERT_THAT(*motionEvent, WithMotionAction(expectedAction)); - ASSERT_EQ(points.size(), motionEvent->getPointerCount()); + 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); } } @@ -8380,8 +8501,7 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) { .build())); mFocusedWindow->consumeMotionDown(); mFocusedWindow->consumeMotionUp(); - mUnfocusedWindow->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_OUTSIDE, - ADISPLAY_ID_DEFAULT, /*flags=*/0); + mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0); // We consumed all events, so no ANR ASSERT_TRUE(mDispatcher->waitForIdle()); mFakePolicy->assertNotifyAnrWasNotCalled(); @@ -8457,8 +8577,7 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout // At the same time, FLAG_WATCH_OUTSIDE_TOUCH targets should not receive any events. TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) { tapOnFocusedWindow(); - mUnfocusedWindow->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_OUTSIDE, - ADISPLAY_ID_DEFAULT, /*flags=*/0); + mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0); // Receive the events, but don't respond std::optional<uint32_t> downEventSequenceNum = mFocusedWindow->receiveEvent(); // ACTION_DOWN ASSERT_TRUE(downEventSequenceNum); @@ -8590,8 +8709,7 @@ TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) { mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {FOCUSED_WINDOW_LOCATION})); - mUnfocusedWindow->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_OUTSIDE, - ADISPLAY_ID_DEFAULT, /*flags=*/0); + mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0); // Touch Window 2 mDispatcher->notifyMotion( @@ -9723,7 +9841,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropNotCancelledIfSomeOtherPointerIsPilf // Receives cancel for first pointer after next pointer down mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); - mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + mSpyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithPointerIds({1}))); mDragWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); mSpyWindow->assertNoEvents(); @@ -9733,13 +9851,13 @@ TEST_F(InputDispatcherDragTests, DragAndDropNotCancelledIfSomeOtherPointerIsPilf mDragWindow->assertNoEvents(); const MotionEvent firstFingerMoveEvent = - MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(60).y(60)) .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, firstFingerMoveEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -9930,8 +10048,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { .displayId(SECOND_DISPLAY_ID) .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); - windowInSecondary->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN, - SECOND_DISPLAY_ID, /*expectedFlag=*/0); + windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID, /*expectedFlag=*/0); // Update window again. mDispatcher->onWindowInfosChanged( {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(), diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index e0a3e94aad..c6536de0d4 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -2894,9 +2894,9 @@ TEST_F(InputDeviceTest, KernelBufferOverflowResetsMappers) { mapper.assertConfigureWasCalled(); mapper.assertResetWasNotCalled(); - RawEvent event{.deviceId = EVENTHUB_ID, + RawEvent event{.when = ARBITRARY_TIME, .readTime = ARBITRARY_TIME, - .when = ARBITRARY_TIME, + .deviceId = EVENTHUB_ID, .type = EV_SYN, .code = SYN_REPORT, .value = 0}; @@ -10971,7 +10971,7 @@ TEST_F(MultiTouchInputMapperTest, Process_MultiTouch_WithInvalidTrackingId) { ASSERT_EQ(uint32_t(1), motionArgs.getPointerCount()); } -TEST_F(MultiTouchInputMapperTest, ResetClearsTouchState) { +TEST_F(MultiTouchInputMapperTest, Reset_PreservesLastTouchState) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); @@ -10994,36 +10994,25 @@ TEST_F(MultiTouchInputMapperTest, ResetClearsTouchState) { ASSERT_NO_FATAL_FAILURE( mFakeListener->assertNotifyMotionWasCalled(WithMotionAction(ACTION_POINTER_1_DOWN))); - // Reset the mapper. When the mapper is reset, the touch state is also cleared. + // Reset the mapper. When the mapper is reset, we expect the current multi-touch state to be + // preserved. Resetting should cancel the ongoing gesture. resetMapper(mapper, ARBITRARY_TIME); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( WithMotionAction(AMOTION_EVENT_ACTION_CANCEL))); - // Move the second slot pointer, and ensure there are no events, because the touch state was - // cleared and no slots should be in use. + // Send a sync to simulate an empty touch frame where nothing changes. The mapper should use + // the existing touch state to generate a down event. processPosition(mapper, 301, 302); processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); - - // Release both fingers. - processId(mapper, INVALID_TRACKING_ID); - processSlot(mapper, FIRST_SLOT); - processId(mapper, INVALID_TRACKING_ID); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); - - // Start a new gesture, and ensure we get a DOWN event for it. - processId(mapper, FIRST_TRACKING_ID); - processPosition(mapper, 200, 300); - processPressure(mapper, RAW_PRESSURE_MAX); - processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPressure(1.f)))); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(ACTION_POINTER_1_DOWN), WithPressure(1.f)))); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } -TEST_F(MultiTouchInputMapperTest, ResetClearsTouchStateWithNoPointersDown) { +TEST_F(MultiTouchInputMapperTest, Reset_PreservesLastTouchState_NoPointersDown) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); @@ -11151,66 +11140,6 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenConfigDisabled_ShouldNotShowDirect ASSERT_FALSE(fakePointerController->isPointerShown()); } -TEST_F(MultiTouchInputMapperTest, SimulateKernelBufferOverflow) { - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(ui::ROTATION_0); - prepareAxes(POSITION | ID | SLOT | PRESSURE); - MultiTouchInputMapper& mapper = constructAndAddMapper<MultiTouchInputMapper>(); - - // First finger down. - processId(mapper, FIRST_TRACKING_ID); - processPosition(mapper, 100, 200); - processPressure(mapper, RAW_PRESSURE_MAX); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( - WithMotionAction(AMOTION_EVENT_ACTION_DOWN))); - - // Assume the kernel buffer overflows, and we get a SYN_DROPPED event. - // This will reset the mapper, and thus also reset the touch state. - process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_DROPPED, 0); - resetMapper(mapper, ARBITRARY_TIME); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( - WithMotionAction(AMOTION_EVENT_ACTION_CANCEL))); - - // Since the touch state was reset, it doesn't know which slots are active, so any movements - // are ignored. - processPosition(mapper, 101, 201); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); - - // Second finger goes down. This is the first active finger, so we get a DOWN event. - processSlot(mapper, SECOND_SLOT); - processId(mapper, SECOND_TRACKING_ID); - processPosition(mapper, 400, 500); - processPressure(mapper, RAW_PRESSURE_MAX); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( - WithMotionAction(AMOTION_EVENT_ACTION_DOWN))); - - // First slot is still ignored, only the second one is active. - processSlot(mapper, FIRST_SLOT); - processPosition(mapper, 102, 202); - processSlot(mapper, SECOND_SLOT); - processPosition(mapper, 401, 501); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( - WithMotionAction(AMOTION_EVENT_ACTION_MOVE))); - - // Both slots up, so we get the UP event for the active pointer. - processSlot(mapper, FIRST_SLOT); - processId(mapper, INVALID_TRACKING_ID); - processSlot(mapper, SECOND_SLOT); - processId(mapper, INVALID_TRACKING_ID); - processSync(mapper); - - ASSERT_NO_FATAL_FAILURE( - mFakeListener->assertNotifyMotionWasCalled(WithMotionAction(AMOTION_EVENT_ACTION_UP))); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); -} - // --- MultiTouchInputMapperTest_ExternalDevice --- class MultiTouchInputMapperTest_ExternalDevice : public MultiTouchInputMapperTest { diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h index 66fdaa4520..8ba497a3ea 100644 --- a/services/inputflinger/tests/TestEventMatchers.h +++ b/services/inputflinger/tests/TestEventMatchers.h @@ -464,6 +464,53 @@ inline WithPointersMatcher WithPointers( return WithPointersMatcher(pointers); } +/// Pointer ids matcher +class WithPointerIdsMatcher { +public: + using is_gtest_matcher = void; + explicit WithPointerIdsMatcher(std::set<int32_t> pointerIds) : mPointerIds(pointerIds) {} + + bool MatchAndExplain(const MotionEvent& event, std::ostream* os) const { + std::set<int32_t> actualPointerIds; + for (size_t pointerIndex = 0; pointerIndex < event.getPointerCount(); pointerIndex++) { + const PointerProperties* properties = event.getPointerProperties(pointerIndex); + actualPointerIds.insert(properties->id); + } + + if (mPointerIds != actualPointerIds) { + *os << "expected pointer ids " << dumpSet(mPointerIds) << ", but got " + << dumpSet(actualPointerIds); + return false; + } + return true; + } + + bool MatchAndExplain(const NotifyMotionArgs& event, std::ostream* os) const { + std::set<int32_t> actualPointerIds; + for (const PointerProperties& properties : event.pointerProperties) { + actualPointerIds.insert(properties.id); + } + + if (mPointerIds != actualPointerIds) { + *os << "expected pointer ids " << dumpSet(mPointerIds) << ", but got " + << dumpSet(actualPointerIds); + return false; + } + return true; + } + + void DescribeTo(std::ostream* os) const { *os << "with pointer ids " << dumpSet(mPointerIds); } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong pointer ids"; } + +private: + const std::set<int32_t> mPointerIds; +}; + +inline WithPointerIdsMatcher WithPointerIds(const std::set<int32_t /*id*/>& pointerIds) { + return WithPointerIdsMatcher(pointerIds); +} + /// Key code class WithKeyCodeMatcher { public: diff --git a/services/powermanager/WorkDuration.cpp b/services/powermanager/WorkDuration.cpp index ef723c229c..bd2b10a149 100644 --- a/services/powermanager/WorkDuration.cpp +++ b/services/powermanager/WorkDuration.cpp @@ -25,8 +25,9 @@ namespace android::os { WorkDuration::WorkDuration(int64_t startTimestampNanos, int64_t totalDurationNanos, int64_t cpuDurationNanos, int64_t gpuDurationNanos) - : workPeriodStartTimestampNanos(startTimestampNanos), + : timestampNanos(0), actualTotalDurationNanos(totalDurationNanos), + workPeriodStartTimestampNanos(startTimestampNanos), actualCpuDurationNanos(cpuDurationNanos), actualGpuDurationNanos(gpuDurationNanos) {} diff --git a/services/powermanager/include/android/WorkDuration.h b/services/powermanager/include/android/WorkDuration.h index 99b5b8b1b4..26a575f834 100644 --- a/services/powermanager/include/android/WorkDuration.h +++ b/services/powermanager/include/android/WorkDuration.h @@ -61,11 +61,11 @@ struct WorkDuration : AWorkDuration, android::Parcelable { return os; } - int64_t workPeriodStartTimestampNanos; + int64_t timestampNanos; int64_t actualTotalDurationNanos; + int64_t workPeriodStartTimestampNanos; int64_t actualCpuDurationNanos; int64_t actualGpuDurationNanos; - int64_t timestampNanos; }; } // namespace android::os diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp index 641ba9f44b..3d2cf293ed 100644 --- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp +++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp @@ -29,9 +29,12 @@ #include <thread> using aidl::android::hardware::power::Boost; +using aidl::android::hardware::power::ChannelConfig; using aidl::android::hardware::power::IPower; using aidl::android::hardware::power::IPowerHintSession; using aidl::android::hardware::power::Mode; +using aidl::android::hardware::power::SessionConfig; +using aidl::android::hardware::power::SessionTag; using android::binder::Status; using namespace android; @@ -53,6 +56,14 @@ public: (int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos, std::shared_ptr<IPowerHintSession>* session), (override)); + MOCK_METHOD(ndk::ScopedAStatus, createHintSessionWithConfig, + (int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, + int64_t durationNanos, SessionTag tag, SessionConfig* config, + std::shared_ptr<IPowerHintSession>* _aidl_return), + (override)); + MOCK_METHOD(ndk::ScopedAStatus, getSessionChannel, + (int32_t tgid, int32_t uid, ChannelConfig* _aidl_return), (override)); + MOCK_METHOD(ndk::ScopedAStatus, closeSessionChannel, (int32_t tgid, int32_t uid), (override)); MOCK_METHOD(ndk::ScopedAStatus, getHintSessionPreferredRate, (int64_t * rate), (override)); MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t * version), (override)); MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string * hash), (override)); diff --git a/services/sensorservice/senserservice_flags.aconfig b/services/sensorservice/senserservice_flags.aconfig index 6b74f6feb2..a3bd0ee483 100644 --- a/services/sensorservice/senserservice_flags.aconfig +++ b/services/sensorservice/senserservice_flags.aconfig @@ -5,4 +5,11 @@ flag { namespace: "sensors" description: "This flag controls if the dynamic sensor data will be clean up after HAL is disconnected." bug: "307782607" +} + +flag { + name: "sensor_device_on_dynamic_sensor_disconnected" + namespace: "sensors" + description: "This flag controls if the callback onDynamicSensorsDisconnected is implemented or not." + bug: "316958439" }
\ No newline at end of file diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h index 5e84be1841..c71c517d94 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h @@ -40,6 +40,9 @@ public: // True if the display is secure virtual bool isSecure() const = 0; + // Sets the secure flag for the display + virtual void setSecure(bool secure) = 0; + // True if the display is virtual virtual bool isVirtual() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index eac5d97df3..c53b46140b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -74,6 +74,7 @@ public: void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override; void createClientCompositionCache(uint32_t cacheSize) override; void applyDisplayBrightness(const bool applyImmediately) override; + void setSecure(bool secure) override; // Internal helpers used by chooseCompositionStrategy() using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h index 7e99ec2f5a..46cb95ef25 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h @@ -33,6 +33,7 @@ public: MOCK_CONST_METHOD0(getId, DisplayId()); MOCK_CONST_METHOD0(isSecure, bool()); + MOCK_METHOD1(setSecure, void(bool)); MOCK_CONST_METHOD0(isVirtual, bool()); MOCK_CONST_METHOD0(getPreferredBootHwcConfigId, int32_t()); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 690d35f068..d907bf538d 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -74,6 +74,10 @@ bool Display::isSecure() const { return getState().isSecure; } +void Display::setSecure(bool secure) { + editState().isSecure = secure; +} + bool Display::isVirtual() const { return VirtualDisplayId::tryCast(mId).has_value(); } @@ -246,7 +250,6 @@ bool Display::chooseCompositionStrategy( } // Get any composition changes requested by the HWC device, and apply them. - std::optional<android::HWComposer::DeviceRequestedChanges> changes; auto& hwc = getCompositionEngine().getHwComposer(); const bool requiresClientComposition = anyLayersRequireClientComposition(); diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp index a18397d8ba..91cfe5dd41 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp @@ -56,7 +56,7 @@ bool isSameStack(const std::vector<const LayerState*>& incomingLayers, } // Do not unflatten if source crop is only moved. - if (FlagManager::getInstance().cache_if_source_crop_layer_only_moved() && + if (FlagManager::getInstance().cache_when_source_crop_layer_only_moved() && incomingLayers[i]->isSourceCropSizeEqual(*(existingLayers[i])) && incomingLayers[i]->getDifferingFields(*(existingLayers[i])) == LayerStateField::SourceCrop) { diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index bf7ed87443..30ba9e439e 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -4094,7 +4094,11 @@ struct OutputComposeSurfacesTest_HandlesProtectedContent : public OutputComposeS }; TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLayers) { - mOutput.mState.isSecure = true; + if (FlagManager::getInstance().display_protected()) { + mOutput.mState.isProtected = true; + } else { + mOutput.mState.isSecure = true; + } mLayer2.mLayerFEState.hasProtectedContent = false; EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true)); EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); @@ -4108,7 +4112,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLa } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) { - mOutput.mState.isSecure = true; + if (FlagManager::getInstance().display_protected()) { + mOutput.mState.isProtected = true; + } else { + mOutput.mState.isSecure = true; + } mLayer2.mLayerFEState.hasProtectedContent = true; EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true)); @@ -4130,7 +4138,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) { } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEverywhere) { - mOutput.mState.isSecure = true; + if (FlagManager::getInstance().display_protected()) { + mOutput.mState.isProtected = true; + } else { + mOutput.mState.isSecure = true; + } mLayer2.mLayerFEState.hasProtectedContent = true; EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true)); EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); @@ -4143,7 +4155,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEveryw } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderSurface) { - mOutput.mState.isSecure = true; + if (FlagManager::getInstance().display_protected()) { + mOutput.mState.isProtected = true; + } else { + mOutput.mState.isSecure = true; + } mLayer2.mLayerFEState.hasProtectedContent = true; EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true)); EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); @@ -4222,6 +4238,7 @@ struct GenerateClientCompositionRequestsTest : public testing::Test { GenerateClientCompositionRequestsTest() { mOutput.mState.needsFiltering = false; + mOutput.mState.isProtected = true; mOutput.setDisplayColorProfileForTest( std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile)); @@ -4246,6 +4263,7 @@ struct GenerateClientCompositionRequestsTest_ThreeLayers mOutput.mState.displaySpace.setOrientation(kDisplayOrientation); mOutput.mState.needsFiltering = false; mOutput.mState.isSecure = false; + mOutput.mState.isProtected = true; for (size_t i = 0; i < mLayers.size(); i++) { mLayers[i].mOutputLayerState.clearClientTarget = false; @@ -4708,7 +4726,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, Region(kDisplayFrame), false, /* needs filtering */ false, /* secure */ - true, /* supports protected content */ + true, /* isProtected */ kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -4721,7 +4739,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, Region(kDisplayFrame), false, /* needs filtering */ false, /* secure */ - true, /* supports protected content */ + true, /* isProtected */ kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -4734,7 +4752,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, Region(kDisplayFrame), false, /* needs filtering */ false, /* secure */ - true, /* supports protected content */ + true, /* isProtected */ kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -4912,7 +4930,7 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq Region(Rect(0, 0, 1000, 1000)), false, /* needs filtering */ true, /* secure */ - true, /* supports protected content */ + true, /* isProtected */ kPortraitViewport, kOutputDataspace, true /* realContentIsVisible */, @@ -4931,7 +4949,7 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq Region(Rect(1000, 0, 2000, 1000)), false, /* needs filtering */ true, /* secure */ - true, /* supports protected content */ + true, /* isProtected */ kPortraitViewport, kOutputDataspace, true /* realContentIsVisible */, diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp index 763b998b3d..d2eff75fb6 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp @@ -244,7 +244,7 @@ TEST_F(FlattenerTest, flattenLayers_ActiveLayersWithLowFpsAreFlattened) { TEST_F(FlattenerTest, unflattenLayers_onlySourceCropMoved) { SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags:: - cache_if_source_crop_layer_only_moved, + cache_when_source_crop_layer_only_moved, true); auto& layerState1 = mTestLayers[0]->layerState; diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 950b05e1da..799d62c19d 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -353,6 +353,10 @@ bool DisplayDevice::isSecure() const { return mCompositionDisplay->isSecure(); } +void DisplayDevice::setSecure(bool secure) { + mCompositionDisplay->setSecure(secure); +} + const Rect DisplayDevice::getBounds() const { return mCompositionDisplay->getState().displaySpace.getBoundsAsRect(); } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index ac390cb8ff..97b56a2f19 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -95,6 +95,7 @@ public: // isSecure indicates whether this display can be trusted to display // secure surfaces. bool isSecure() const; + void setSecure(bool secure); int getWidth() const; int getHeight() const; diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 24a9e22a2b..704ece516d 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -165,8 +165,7 @@ Error Display::getChangedCompositionTypes(std::unordered_map<HWC2::Layer*, Compo auto intError = mComposer.getChangedCompositionTypes( mId, &layerIds, &types); uint32_t numElements = layerIds.size(); - auto error = static_cast<Error>(intError); - error = static_cast<Error>(intError); + const auto error = static_cast<Error>(intError); if (error != Error::NONE) { return error; } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 3ffd8ea316..cf1c3c10b7 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -77,6 +77,8 @@ using aidl::android::hardware::graphics::common::HdrConversionCapability; using aidl::android::hardware::graphics::common::HdrConversionStrategy; using aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::DisplayCapability; +using aidl::android::hardware::graphics::composer3::VrrConfig; +using namespace std::string_literals; namespace hal = android::hardware::graphics::composer::hal; namespace android { @@ -89,7 +91,8 @@ HWComposer::HWComposer(std::unique_ptr<Hwc2::Composer> composer) : mComposer(std::move(composer)), mMaxVirtualDisplayDimension(static_cast<size_t>(sysprop::max_virtual_display_dimension(0))), mUpdateDeviceProductInfoOnHotplugReconnect( - sysprop::update_device_product_info_on_hotplug_reconnect(false)) {} + sysprop::update_device_product_info_on_hotplug_reconnect(false)), + mEnableVrrTimeout(base::GetBoolProperty("debug.sf.vrr_timeout_hint_enabled"s, false)) {} HWComposer::HWComposer(const std::string& composerServiceName) : HWComposer(Hwc2::Composer::create(composerServiceName)) {} @@ -299,6 +302,10 @@ std::vector<HWComposer::HWCDisplayMode> HWComposer::getModesFromDisplayConfigura hwcMode.dpiY = config.dpi->y; } + if (!mEnableVrrTimeout) { + hwcMode.vrrConfig->notifyExpectedPresentConfig = {}; + } + modes.push_back(hwcMode); } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 4ca528a6e7..fb32ff45e1 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -491,6 +491,7 @@ public: private: // For unit tests friend TestableSurfaceFlinger; + friend HWComposerTest; struct DisplayData { std::unique_ptr<HWC2::Display> hwcDisplay; @@ -542,6 +543,7 @@ private: const size_t mMaxVirtualDisplayDimension; const bool mUpdateDeviceProductInfoOnHotplugReconnect; + bool mEnableVrrTimeout; }; } // namespace impl diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h index 31c2833229..e3d962237b 100644 --- a/services/surfaceflinger/DisplayHardware/Hal.h +++ b/services/surfaceflinger/DisplayHardware/Hal.h @@ -169,10 +169,8 @@ inline std::string to_string( out << "}, "; out << "notifyExpectedPresentConfig={"; if (vrrConfig->notifyExpectedPresentConfig) { - out << "notifyExpectedPresentHeadsUpNs=" - << vrrConfig->notifyExpectedPresentConfig->notifyExpectedPresentHeadsUpNs - << ", notifyExpectedPresentTimeoutNs=" - << vrrConfig->notifyExpectedPresentConfig->notifyExpectedPresentTimeoutNs; + out << "headsUpNs=" << vrrConfig->notifyExpectedPresentConfig->headsUpNs + << ", timeoutNs=" << vrrConfig->notifyExpectedPresentConfig->timeoutNs; } out << "}}"; return out.str(); diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index dd228b4523..a0c943ba72 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -31,10 +31,6 @@ #include <utils/Mutex.h> #include <utils/Trace.h> -#include <aidl/android/hardware/power/IPower.h> -#include <aidl/android/hardware/power/IPowerHintSession.h> -#include <aidl/android/hardware/power/WorkDuration.h> - #include <binder/IServiceManager.h> #include "../SurfaceFlingerProperties.h" diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h index 0276e44986..bbe51cc09d 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h @@ -25,9 +25,14 @@ #include <ui/FenceTime.h> #include <utils/Mutex.h> +// FMQ library in IPower does questionable conversions +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" #include <aidl/android/hardware/power/IPower.h> -#include <compositionengine/impl/OutputCompositionState.h> #include <powermanager/PowerHalController.h> +#pragma clang diagnostic pop + +#include <compositionengine/impl/OutputCompositionState.h> #include <scheduler/Time.h> #include <ui/DisplayIdentification.h> #include "../Scheduler/OneShotTimer.h" diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 803299cf6f..d0e2d7a451 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -390,6 +390,22 @@ void SurfaceFrame::setGpuComposition() { mGpuComposition = true; } +// TODO(b/316171339): migrate from perfetto side +bool SurfaceFrame::isSelfJanky() const { + int32_t jankType = getJankType().value_or(JankType::None); + + if (jankType == JankType::None) { + return false; + } + + int32_t jankBitmask = JankType::AppDeadlineMissed | JankType::Unknown; + if (jankType & jankBitmask) { + return true; + } + + return false; +} + std::optional<int32_t> SurfaceFrame::getJankType() const { std::scoped_lock lock(mMutex); if (mPresentState == PresentState::Dropped) { @@ -1113,20 +1129,23 @@ void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid, } void FrameTimeline::DisplayFrame::addSkippedFrame(pid_t surfaceFlingerPid, nsecs_t monoBootOffset, - nsecs_t previousActualPresentTime) const { + nsecs_t previousPredictionPresentTime) const { nsecs_t skippedFrameStartTime = 0, skippedFramePresentTime = 0; const constexpr float kThresh = 0.5f; const constexpr float kRange = 1.5f; for (auto& surfaceFrame : mSurfaceFrames) { - if (previousActualPresentTime != 0 && - static_cast<float>(mSurfaceFlingerActuals.presentTime - previousActualPresentTime) >= + if (previousPredictionPresentTime != 0 && + static_cast<float>(mSurfaceFlingerPredictions.presentTime - + previousPredictionPresentTime) >= static_cast<float>(mRenderRate.getPeriodNsecs()) * kRange && static_cast<float>(surfaceFrame->getPredictions().presentTime) <= - (static_cast<float>(mSurfaceFlingerActuals.presentTime) - + (static_cast<float>(mSurfaceFlingerPredictions.presentTime) - kThresh * static_cast<float>(mRenderRate.getPeriodNsecs())) && static_cast<float>(surfaceFrame->getPredictions().presentTime) >= - (static_cast<float>(previousActualPresentTime) - - kThresh * static_cast<float>(mRenderRate.getPeriodNsecs()))) { + (static_cast<float>(previousPredictionPresentTime) - + kThresh * static_cast<float>(mRenderRate.getPeriodNsecs())) && + // sf skipped frame is not considered if app is self janked + !surfaceFrame->isSelfJanky()) { skippedFrameStartTime = surfaceFrame->getPredictions().endTime; skippedFramePresentTime = surfaceFrame->getPredictions().presentTime; break; @@ -1215,18 +1234,18 @@ void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid, }); } -void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid, nsecs_t monoBootOffset, - nsecs_t previousActualPresentTime) const { +nsecs_t FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid, nsecs_t monoBootOffset, + nsecs_t previousPredictionPresentTime) const { if (mSurfaceFrames.empty()) { // We don't want to trace display frames without any surface frames updates as this cannot // be janky - return; + return previousPredictionPresentTime; } if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) { // DisplayFrame should not have an invalid token. ALOGE("Cannot trace DisplayFrame with invalid token"); - return; + return previousPredictionPresentTime; } if (mPredictionState == PredictionState::Valid) { @@ -1241,8 +1260,9 @@ void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid, nsecs_t monoBoo } if (FlagManager::getInstance().add_sf_skipped_frames_to_trace()) { - addSkippedFrame(surfaceFlingerPid, monoBootOffset, previousActualPresentTime); + addSkippedFrame(surfaceFlingerPid, monoBootOffset, previousPredictionPresentTime); } + return mSurfaceFlingerPredictions.presentTime; } float FrameTimeline::computeFps(const std::unordered_set<int32_t>& layerIds) { @@ -1333,8 +1353,9 @@ void FrameTimeline::flushPendingPresentFences() { const auto& pendingPresentFence = *mPendingPresentFences.begin(); const nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID; auto& displayFrame = pendingPresentFence.second; - displayFrame->onPresent(signalTime, mPreviousPresentTime); - displayFrame->trace(mSurfaceFlingerPid, monoBootOffset, mPreviousPresentTime); + displayFrame->onPresent(signalTime, mPreviousActualPresentTime); + mPreviousPredictionPresentTime = displayFrame->trace(mSurfaceFlingerPid, monoBootOffset, + mPreviousPredictionPresentTime); mPendingPresentFences.erase(mPendingPresentFences.begin()); } @@ -1349,9 +1370,10 @@ void FrameTimeline::flushPendingPresentFences() { } auto& displayFrame = pendingPresentFence.second; - displayFrame->onPresent(signalTime, mPreviousPresentTime); - displayFrame->trace(mSurfaceFlingerPid, monoBootOffset, mPreviousPresentTime); - mPreviousPresentTime = signalTime; + displayFrame->onPresent(signalTime, mPreviousActualPresentTime); + mPreviousPredictionPresentTime = displayFrame->trace(mSurfaceFlingerPid, monoBootOffset, + mPreviousPredictionPresentTime); + mPreviousActualPresentTime = signalTime; mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i)); --i; diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index b5047a3467..a76f7d477a 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -165,6 +165,8 @@ public: TraceCookieCounter* traceCookieCounter, bool isBuffer, GameMode); ~SurfaceFrame() = default; + bool isSelfJanky() const; + // Returns std::nullopt if the frame hasn't been classified yet. // Used by both SF and FrameTimeline. std::optional<int32_t> getJankType() const; @@ -381,8 +383,8 @@ public: // Emits a packet for perfetto tracing. The function body will be executed only if tracing // is enabled. monoBootOffset is the difference between SYSTEM_TIME_BOOTTIME // and SYSTEM_TIME_MONOTONIC. - void trace(pid_t surfaceFlingerPid, nsecs_t monoBootOffset, - nsecs_t previousActualPresentTime) const; + nsecs_t trace(pid_t surfaceFlingerPid, nsecs_t monoBootOffset, + nsecs_t previousPredictionPresentTime) const; // Sets the token, vsyncPeriod, predictions and SF start time. void onSfWakeUp(int64_t token, Fps refreshRate, Fps renderRate, std::optional<TimelineItem> predictions, nsecs_t wakeUpTime); @@ -508,7 +510,8 @@ private: uint32_t mMaxDisplayFrames; std::shared_ptr<TimeStats> mTimeStats; const pid_t mSurfaceFlingerPid; - nsecs_t mPreviousPresentTime = 0; + nsecs_t mPreviousActualPresentTime = 0; + nsecs_t mPreviousPredictionPresentTime = 0; const JankClassificationThresholds mJankClassificationThresholds; static constexpr uint32_t kDefaultMaxDisplayFrames = 64; // The initial container size for the vector<SurfaceFrames> inside display frame. Although diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp index 1e5a6fbd1e..821ac0cf88 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp @@ -190,8 +190,12 @@ bool LayerHierarchy::hasRelZLoop(uint32_t& outInvalidRelativeRoot) const { return outInvalidRelativeRoot != UNASSIGNED_LAYER_ID; } -LayerHierarchyBuilder::LayerHierarchyBuilder( - const std::vector<std::unique_ptr<RequestedLayerState>>& layers) { +void LayerHierarchyBuilder::init(const std::vector<std::unique_ptr<RequestedLayerState>>& layers) { + mLayerIdToHierarchy.clear(); + mHierarchies.clear(); + mRoot = nullptr; + mOffscreenRoot = nullptr; + mHierarchies.reserve(layers.size()); mLayerIdToHierarchy.reserve(layers.size()); for (auto& layer : layers) { @@ -202,6 +206,7 @@ LayerHierarchyBuilder::LayerHierarchyBuilder( onLayerAdded(layer.get()); } detachHierarchyFromRelativeParent(&mOffscreenRoot); + mInitialized = true; } void LayerHierarchyBuilder::attachToParent(LayerHierarchy* hierarchy) { @@ -332,7 +337,7 @@ void LayerHierarchyBuilder::updateMirrorLayer(RequestedLayerState* layer) { } } -void LayerHierarchyBuilder::update( +void LayerHierarchyBuilder::doUpdate( const std::vector<std::unique_ptr<RequestedLayerState>>& layers, const std::vector<std::unique_ptr<RequestedLayerState>>& destroyedLayers) { // rebuild map @@ -381,6 +386,32 @@ void LayerHierarchyBuilder::update( attachHierarchyToRelativeParent(&mRoot); } +void LayerHierarchyBuilder::update(LayerLifecycleManager& layerLifecycleManager) { + if (!mInitialized) { + ATRACE_NAME("LayerHierarchyBuilder:init"); + init(layerLifecycleManager.getLayers()); + } else if (layerLifecycleManager.getGlobalChanges().test( + RequestedLayerState::Changes::Hierarchy)) { + ATRACE_NAME("LayerHierarchyBuilder:update"); + doUpdate(layerLifecycleManager.getLayers(), layerLifecycleManager.getDestroyedLayers()); + } else { + return; // nothing to do + } + + uint32_t invalidRelativeRoot; + bool hasRelZLoop = mRoot.hasRelZLoop(invalidRelativeRoot); + while (hasRelZLoop) { + ATRACE_NAME("FixRelZLoop"); + TransactionTraceWriter::getInstance().invoke("relz_loop_detected", + /*overwrite=*/false); + layerLifecycleManager.fixRelativeZLoop(invalidRelativeRoot); + // reinitialize the hierarchy with the updated layer data + init(layerLifecycleManager.getLayers()); + // check if we have any remaining loops + hasRelZLoop = mRoot.hasRelZLoop(invalidRelativeRoot); + } +} + const LayerHierarchy& LayerHierarchyBuilder::getHierarchy() const { return mRoot; } diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h index ba2e262baf..a1c73c38b0 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h @@ -17,6 +17,7 @@ #pragma once #include "FrontEnd/LayerCreationArgs.h" +#include "FrontEnd/LayerLifecycleManager.h" #include "RequestedLayerState.h" #include "ftl/small_vector.h" @@ -197,9 +198,8 @@ private: // hierarchy from a list of RequestedLayerState and associated change flags. class LayerHierarchyBuilder { public: - LayerHierarchyBuilder(const std::vector<std::unique_ptr<RequestedLayerState>>&); - void update(const std::vector<std::unique_ptr<RequestedLayerState>>& layers, - const std::vector<std::unique_ptr<RequestedLayerState>>& destroyedLayers); + LayerHierarchyBuilder() = default; + void update(LayerLifecycleManager& layerLifecycleManager); LayerHierarchy getPartialHierarchy(uint32_t, bool childrenOnly) const; const LayerHierarchy& getHierarchy() const; const LayerHierarchy& getOffscreenHierarchy() const; @@ -213,14 +213,18 @@ private: void detachFromRelativeParent(LayerHierarchy*); void attachHierarchyToRelativeParent(LayerHierarchy*); void detachHierarchyFromRelativeParent(LayerHierarchy*); - + void init(const std::vector<std::unique_ptr<RequestedLayerState>>&); + void doUpdate(const std::vector<std::unique_ptr<RequestedLayerState>>& layers, + const std::vector<std::unique_ptr<RequestedLayerState>>& destroyedLayers); void onLayerDestroyed(RequestedLayerState* layer); void updateMirrorLayer(RequestedLayerState* layer); LayerHierarchy* getHierarchyFromId(uint32_t layerId, bool crashOnFailure = true); + std::unordered_map<uint32_t, LayerHierarchy*> mLayerIdToHierarchy; std::vector<std::unique_ptr<LayerHierarchy>> mHierarchies; LayerHierarchy mRoot{nullptr}; LayerHierarchy mOffscreenRoot{nullptr}; + bool mInitialized = false; }; } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 693a357de5..6e862b4a1e 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -100,6 +100,11 @@ std::string toString(const DisplayEventReceiver::Event& event) { case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: return StringPrintf("ModeChanged{displayId=%s, modeId=%u}", to_string(event.header.displayId).c_str(), event.modeChange.modeId); + case DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE: + return StringPrintf("HdcpLevelsChange{displayId=%s, connectedLevel=%d, maxLevel=%d}", + to_string(event.header.displayId).c_str(), + event.hdcpLevelsChange.connectedLevel, + event.hdcpLevelsChange.maxLevel); default: return "Event{}"; } @@ -170,6 +175,20 @@ DisplayEventReceiver::Event makeFrameRateOverrideFlushEvent(PhysicalDisplayId di }}; } +DisplayEventReceiver::Event makeHdcpLevelsChange(PhysicalDisplayId displayId, + int32_t connectedLevel, int32_t maxLevel) { + return DisplayEventReceiver::Event{ + .header = + DisplayEventReceiver::Event::Header{ + .type = DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE, + .displayId = displayId, + .timestamp = systemTime(), + }, + .hdcpLevelsChange.connectedLevel = connectedLevel, + .hdcpLevelsChange.maxLevel = maxLevel, + }; +} + } // namespace EventThreadConnection::EventThreadConnection(EventThread* eventThread, uid_t callingUid, @@ -301,7 +320,7 @@ void EventThread::setDuration(std::chrono::nanoseconds workDuration, mVsyncRegistration.update({.workDuration = mWorkDuration.get().count(), .readyDuration = mReadyDuration.count(), - .earliestVsync = mLastVsyncCallbackTime.ns()}); + .lastVsync = mLastVsyncCallbackTime.ns()}); } sp<EventThreadConnection> EventThread::createEventConnection( @@ -442,6 +461,14 @@ void EventThread::onFrameRateOverridesChanged(PhysicalDisplayId displayId, mCondition.notify_all(); } +void EventThread::onHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel, + int32_t maxLevel) { + std::lock_guard<std::mutex> lock(mMutex); + + mPendingEvents.push_back(makeHdcpLevelsChange(displayId, connectedLevel, maxLevel)); + mCondition.notify_all(); +} + void EventThread::threadMain(std::unique_lock<std::mutex>& lock) { DisplayEventConsumers consumers; @@ -501,7 +528,7 @@ void EventThread::threadMain(std::unique_lock<std::mutex>& lock) { const auto scheduleResult = mVsyncRegistration.schedule({.workDuration = mWorkDuration.get().count(), .readyDuration = mReadyDuration.count(), - .earliestVsync = mLastVsyncCallbackTime.ns()}); + .lastVsync = mLastVsyncCallbackTime.ns()}); LOG_ALWAYS_FATAL_IF(!scheduleResult, "Error scheduling callback"); } else { mVsyncRegistration.cancel(); @@ -757,7 +784,7 @@ scheduler::VSyncCallbackRegistration EventThread::onNewVsyncScheduleInternal( if (reschedule) { mVsyncRegistration.schedule({.workDuration = mWorkDuration.get().count(), .readyDuration = mReadyDuration.count(), - .earliestVsync = mLastVsyncCallbackTime.ns()}); + .lastVsync = mLastVsyncCallbackTime.ns()}); } return oldRegistration; } diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 7842318e2e..8970103a7c 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -131,6 +131,9 @@ public: const sp<EventThreadConnection>& connection) const = 0; virtual void onNewVsyncSchedule(std::shared_ptr<scheduler::VsyncSchedule>) = 0; + + virtual void onHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel, + int32_t maxLevel) = 0; }; struct IEventThreadCallback { @@ -177,6 +180,9 @@ public: void onNewVsyncSchedule(std::shared_ptr<scheduler::VsyncSchedule>) override EXCLUDES(mMutex); + void onHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel, + int32_t maxLevel) override; + private: friend EventThreadTest; diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index 18c0a696d5..cf8b3bfdbd 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -125,7 +125,7 @@ std::unique_ptr<scheduler::VSyncCallbackRegistration> MessageQueue::onNewVsyncSc mVsync.scheduledFrameTime = mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(), .readyDuration = 0, - .earliestVsync = mVsync.lastCallbackTime.ns()}); + .lastVsync = mVsync.lastCallbackTime.ns()}); } return oldRegistration; } @@ -143,7 +143,7 @@ void MessageQueue::setDuration(std::chrono::nanoseconds workDuration) { mVsync.scheduledFrameTime = mVsync.registration->update({.workDuration = mVsync.workDuration.get().count(), .readyDuration = 0, - .earliestVsync = mVsync.lastCallbackTime.ns()}); + .lastVsync = mVsync.lastCallbackTime.ns()}); } void MessageQueue::waitMessage() { @@ -196,7 +196,7 @@ void MessageQueue::scheduleFrame() { mVsync.scheduledFrameTime = mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(), .readyDuration = 0, - .earliestVsync = mVsync.lastCallbackTime.ns()}); + .lastVsync = mVsync.lastCallbackTime.ns()}); } auto MessageQueue::getScheduledFrameTime() const -> std::optional<Clock::time_point> { diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index ce59a04808..bfc47e67a6 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -412,6 +412,17 @@ void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDis thread->onFrameRateOverridesChanged(displayId, std::move(overrides)); } +void Scheduler::onHdcpLevelsChanged(ConnectionHandle handle, PhysicalDisplayId displayId, + int32_t connectedLevel, int32_t maxLevel) { + android::EventThread* thread; + { + std::lock_guard<std::mutex> lock(mConnectionsLock); + RETURN_IF_INVALID_HANDLE(handle); + thread = mConnections[handle].thread.get(); + } + thread->onHdcpLevelsChanged(displayId, connectedLevel, maxLevel); +} + void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, const FrameRateMode& mode) { { std::lock_guard<std::mutex> lock(mPolicyLock); @@ -600,8 +611,10 @@ Fps Scheduler::getNextFrameInterval(PhysicalDisplayId id, const Display& display = *displayOpt; const nsecs_t threshold = display.selectorPtr->getActiveMode().modePtr->getVsyncRate().getPeriodNsecs() / 2; - const nsecs_t nextVsyncTime = display.schedulePtr->getTracker().nextAnticipatedVSyncTimeFrom( - currentExpectedPresentTime.ns() + threshold); + const nsecs_t nextVsyncTime = + display.schedulePtr->getTracker() + .nextAnticipatedVSyncTimeFrom(currentExpectedPresentTime.ns() + threshold, + currentExpectedPresentTime.ns()); return Fps::fromPeriodNsecs(nextVsyncTime - currentExpectedPresentTime.ns()); } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index ce585c624a..a29d153516 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -173,6 +173,8 @@ public: void onFrameRateOverridesChanged(ConnectionHandle, PhysicalDisplayId) EXCLUDES(mConnectionsLock); + void onHdcpLevelsChanged(ConnectionHandle, PhysicalDisplayId, int32_t, int32_t); + // Modifies work duration in the event thread. void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration); diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h index c3a952f689..f978016c9e 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatch.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h @@ -84,8 +84,8 @@ public: * able to provide the ready-by time (deadline) on the callback. * For internal clients, we don't need to add additional padding, so * readyDuration will typically be 0. - * @earliestVsync: The targeted display time. This will be snapped to the closest - * predicted vsync time after earliestVsync. + * @lastVsync: The targeted display time. This will be snapped to the closest + * predicted vsync time after lastVsync. * * callback will be dispatched at 'workDuration + readyDuration' nanoseconds before a vsync * event. @@ -93,11 +93,11 @@ public: struct ScheduleTiming { nsecs_t workDuration = 0; nsecs_t readyDuration = 0; - nsecs_t earliestVsync = 0; + nsecs_t lastVsync = 0; bool operator==(const ScheduleTiming& other) const { return workDuration == other.workDuration && readyDuration == other.readyDuration && - earliestVsync == other.earliestVsync; + lastVsync == other.lastVsync; } bool operator!=(const ScheduleTiming& other) const { return !(*this == other); } @@ -109,12 +109,12 @@ public: * The callback will be dispatched at 'workDuration + readyDuration' nanoseconds before a vsync * event. * - * The caller designates the earliest vsync event that should be targeted by the earliestVsync + * The caller designates the earliest vsync event that should be targeted by the lastVsync * parameter. * The callback will be scheduled at (workDuration + readyDuration - predictedVsync), where - * predictedVsync is the first vsync event time where ( predictedVsync >= earliestVsync ). + * predictedVsync is the first vsync event time where ( predictedVsync >= lastVsync ). * - * If (workDuration + readyDuration - earliestVsync) is in the past, or if a callback has + * If (workDuration + readyDuration - lastVsync) is in the past, or if a callback has * already been dispatched for the predictedVsync, an error will be returned. * * It is valid to reschedule a callback to a different time. diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp index ef30887037..5cb0ffbfb7 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp @@ -45,8 +45,11 @@ nsecs_t getExpectedCallbackTime(nsecs_t nextVsyncTime, nsecs_t getExpectedCallbackTime(VSyncTracker& tracker, nsecs_t now, const VSyncDispatch::ScheduleTiming& timing) { - const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom( - std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration)); + const auto nextVsyncTime = + tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.lastVsync, + now + timing.workDuration + + timing.readyDuration), + timing.lastVsync); return getExpectedCallbackTime(nextVsyncTime, timing); } @@ -93,8 +96,11 @@ std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const { ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing, VSyncTracker& tracker, nsecs_t now) { - auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom( - std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration)); + auto nextVsyncTime = + tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.lastVsync, + now + timing.workDuration + + timing.readyDuration), + timing.lastVsync); auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration; bool const wouldSkipAVsyncTarget = @@ -139,11 +145,13 @@ nsecs_t VSyncDispatchTimerQueueEntry::adjustVsyncIfNeeded(VSyncTracker& tracker, bool const nextVsyncTooClose = mLastDispatchTime && (nextVsyncTime - *mLastDispatchTime + mMinVsyncDistance) <= currentPeriod; if (alreadyDispatchedForVsync) { - return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance); + return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance, + *mLastDispatchTime); } if (nextVsyncTooClose) { - return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + currentPeriod); + return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + currentPeriod, + *mLastDispatchTime + currentPeriod); } return nextVsyncTime; @@ -160,11 +168,12 @@ void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) { } const auto earliestReadyBy = now + mScheduleTiming.workDuration + mScheduleTiming.readyDuration; - const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.earliestVsync); + const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.lastVsync); const auto nextVsyncTime = adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/ - tracker.nextAnticipatedVSyncTimeFrom(earliestVsync)); + tracker.nextAnticipatedVSyncTimeFrom(earliestVsync, + mScheduleTiming.lastVsync)); const auto nextReadyTime = nextVsyncTime - mScheduleTiming.readyDuration; const auto nextWakeupTime = nextReadyTime - mScheduleTiming.workDuration; @@ -214,10 +223,10 @@ void VSyncDispatchTimerQueueEntry::dump(std::string& result) const { StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(), mRunning ? "(in callback function)" : "", armedInfo.c_str()); StringAppendF(&result, - "\t\t\tworkDuration: %.2fms readyDuration: %.2fms earliestVsync: %.2fms relative " + "\t\t\tworkDuration: %.2fms readyDuration: %.2fms lastVsync: %.2fms relative " "to now\n", mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f, - (mScheduleTiming.earliestVsync - systemTime()) / 1e6f); + (mScheduleTiming.lastVsync - systemTime()) / 1e6f); if (mLastDispatchTime) { StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n", @@ -237,6 +246,7 @@ VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk, VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() { std::lock_guard lock(mMutex); + mRunning = false; cancelTimer(); for (auto& [_, entry] : mCallbacks) { ALOGE("Forgot to unregister a callback on VSyncDispatch!"); @@ -305,6 +315,10 @@ void VSyncDispatchTimerQueue::timerCallback() { std::vector<Invocation> invocations; { std::lock_guard lock(mMutex); + if (!mRunning) { + ALOGD("TimerQueue is not running. Skipping callback."); + return; + } auto const now = mTimeKeeper->now(); mLastTimerCallback = now; for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) { diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h index e0fb8f9f86..3d08410df7 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h @@ -148,6 +148,10 @@ private: std::mutex mutable mMutex; + // During VSyncDispatchTimerQueue deconstruction, skip timerCallback to + // avoid crash + bool mRunning = true; + static constexpr nsecs_t kInvalidTime = std::numeric_limits<int64_t>::max(); std::unique_ptr<TimeKeeper> const mTimeKeeper; VsyncSchedule::TrackerPtr mTracker; diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index 0d79a390a7..28e35de465 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -253,7 +253,7 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { } auto VSyncPredictor::getVsyncSequenceLocked(nsecs_t timestamp) const -> VsyncSequence { - const auto vsync = nextAnticipatedVSyncTimeFromLocked(timestamp); + const auto vsync = snapToVsync(timestamp); if (!mLastVsyncSequence) return {vsync, 0}; const auto [slope, _] = getVSyncPredictionModelLocked(); @@ -263,7 +263,7 @@ auto VSyncPredictor::getVsyncSequenceLocked(nsecs_t timestamp) const -> VsyncSeq return {vsync, vsyncSequence}; } -nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFromLocked(nsecs_t timePoint) const { +nsecs_t VSyncPredictor::snapToVsync(nsecs_t timePoint) const { auto const [slope, intercept] = getVSyncPredictionModelLocked(); if (mTimestamps.empty()) { @@ -299,9 +299,29 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFromLocked(nsecs_t timePoint) co return prediction; } -nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { +nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint, + std::optional<nsecs_t> lastVsyncOpt) const { + ATRACE_CALL(); std::lock_guard lock(mMutex); + const auto currentPeriod = mRateMap.find(idealPeriod())->second.slope; + const auto threshold = currentPeriod / 2; + const auto minFramePeriod = minFramePeriodLocked().ns(); + const auto lastFrameMissed = + lastVsyncOpt && std::abs(*lastVsyncOpt - mLastMissedVsync.ns()) < threshold; + const nsecs_t baseTime = + FlagManager::getInstance().vrr_config() && !lastFrameMissed && lastVsyncOpt + ? std::max(timePoint, *lastVsyncOpt + minFramePeriod - threshold) + : timePoint; + const auto vsyncTime = snapToVsyncAlignedWithRenderRate(baseTime); + if (FlagManager::getInstance().vrr_config()) { + const auto vsyncTimePoint = TimePoint::fromNs(vsyncTime); + const Fps renderRate = mRenderRateOpt ? *mRenderRateOpt : mDisplayModePtr->getPeakFps(); + mVsyncTrackerCallback.onVsyncGenerated(vsyncTimePoint, mDisplayModePtr, renderRate); + } + return vsyncTime; +} +nsecs_t VSyncPredictor::snapToVsyncAlignedWithRenderRate(nsecs_t timePoint) const { // update the mLastVsyncSequence for reference point mLastVsyncSequence = getVsyncSequenceLocked(timePoint); @@ -325,30 +345,12 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { }(); if (renderRatePhase == 0) { - const auto vsyncTime = mLastVsyncSequence->vsyncTime; - if (FlagManager::getInstance().vrr_config()) { - const auto vsyncTimePoint = TimePoint::fromNs(vsyncTime); - ATRACE_FORMAT("%s InPhase vsyncIn %.2fms", __func__, - ticks<std::milli, float>(vsyncTimePoint - TimePoint::now())); - const Fps renderRate = mRenderRateOpt ? *mRenderRateOpt : mDisplayModePtr->getPeakFps(); - mVsyncTrackerCallback.onVsyncGenerated(vsyncTimePoint, mDisplayModePtr, renderRate); - } - return vsyncTime; + return mLastVsyncSequence->vsyncTime; } auto const [slope, intercept] = getVSyncPredictionModelLocked(); const auto approximateNextVsync = mLastVsyncSequence->vsyncTime + slope * renderRatePhase; - const auto nextAnticipatedVsyncTime = - nextAnticipatedVSyncTimeFromLocked(approximateNextVsync - slope / 2); - if (FlagManager::getInstance().vrr_config()) { - const auto nextAnticipatedVsyncTimePoint = TimePoint::fromNs(nextAnticipatedVsyncTime); - ATRACE_FORMAT("%s outOfPhase vsyncIn %.2fms", __func__, - ticks<std::milli, float>(nextAnticipatedVsyncTimePoint - TimePoint::now())); - const Fps renderRate = mRenderRateOpt ? *mRenderRateOpt : mDisplayModePtr->getPeakFps(); - mVsyncTrackerCallback.onVsyncGenerated(nextAnticipatedVsyncTimePoint, mDisplayModePtr, - renderRate); - } - return nextAnticipatedVsyncTime; + return snapToVsync(approximateNextVsync - slope / 2); } /* @@ -403,7 +405,7 @@ void VSyncPredictor::setDisplayModePtr(ftl::NonNull<DisplayModePtr> modePtr) { : std::nullopt; ALOGV("%s %s: DisplayMode %s notifyExpectedPresentTimeout %s", __func__, to_string(mId).c_str(), to_string(*modePtr).c_str(), - timeout ? std::to_string(timeout->notifyExpectedPresentTimeoutNs).c_str() : "N/A"); + timeout ? std::to_string(timeout->timeoutNs).c_str() : "N/A"); std::lock_guard lock(mMutex); mDisplayModePtr = modePtr; @@ -451,6 +453,7 @@ void VSyncPredictor::ensureMinFrameDurationIsKept(TimePoint expectedPresentTime, if (mLastVsyncSequence) { mLastVsyncSequence->vsyncTime += phase.ns(); } + mPastExpectedPresentTimes.clear(); } } } @@ -468,23 +471,17 @@ void VSyncPredictor::onFrameBegin(TimePoint expectedPresentTime, lastConfirmedPresentTime.ns()) / 1e6f); } - mPastExpectedPresentTimes.push_back(expectedPresentTime); - const auto currentPeriod = mRateMap.find(idealPeriod())->second.slope; const auto threshold = currentPeriod / 2; + mPastExpectedPresentTimes.push_back(expectedPresentTime); - const auto minFramePeriod = minFramePeriodLocked().ns(); while (!mPastExpectedPresentTimes.empty()) { const auto front = mPastExpectedPresentTimes.front().ns(); - const bool frontIsLastConfirmed = - std::abs(front - lastConfirmedPresentTime.ns()) < threshold; - const bool frontIsBeforeConfirmed = - front < lastConfirmedPresentTime.ns() - minFramePeriod + threshold; - if (frontIsLastConfirmed || frontIsBeforeConfirmed) { + const bool frontIsBeforeConfirmed = front < lastConfirmedPresentTime.ns() + threshold; + if (frontIsBeforeConfirmed) { if (CC_UNLIKELY(mTraceOn)) { ATRACE_FORMAT_INSTANT("Discarding old vsync - %.2f before last signaled fence", - static_cast<float>(lastConfirmedPresentTime.ns() - - mPastExpectedPresentTimes.front().ns()) / + static_cast<float>(lastConfirmedPresentTime.ns() - front) / 1e6f); } mPastExpectedPresentTimes.pop_front(); @@ -508,6 +505,7 @@ void VSyncPredictor::onFrameMissed(TimePoint expectedPresentTime) { TimePoint::fromNs(expectedPresentTime.ns() + currentPeriod); ensureMinFrameDurationIsKept(expectedPresentTime, lastConfirmedPresentTime); + mLastMissedVsync = expectedPresentTime; } VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModel() const { diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h index 72a343112a..919100363f 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.h +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h @@ -45,7 +45,9 @@ public: ~VSyncPredictor(); bool addVsyncTimestamp(nsecs_t timestamp) final EXCLUDES(mMutex); - nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final EXCLUDES(mMutex); + nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint, + std::optional<nsecs_t> lastVsyncOpt = {}) const final + EXCLUDES(mMutex); nsecs_t currentPeriod() const final EXCLUDES(mMutex); Period minFramePeriod() const final EXCLUDES(mMutex); void resetModel() final EXCLUDES(mMutex); @@ -87,7 +89,8 @@ private: size_t next(size_t i) const REQUIRES(mMutex); bool validate(nsecs_t timestamp) const REQUIRES(mMutex); Model getVSyncPredictionModelLocked() const REQUIRES(mMutex); - nsecs_t nextAnticipatedVSyncTimeFromLocked(nsecs_t timePoint) const REQUIRES(mMutex); + nsecs_t snapToVsync(nsecs_t timePoint) const REQUIRES(mMutex); + nsecs_t snapToVsyncAlignedWithRenderRate(nsecs_t timePoint) const REQUIRES(mMutex); bool isVSyncInPhaseLocked(nsecs_t timePoint, unsigned divisor) const REQUIRES(mMutex); Period minFramePeriodLocked() const REQUIRES(mMutex); void ensureMinFrameDurationIsKept(TimePoint, TimePoint) REQUIRES(mMutex); @@ -120,6 +123,8 @@ private: mutable std::optional<VsyncSequence> mLastVsyncSequence GUARDED_BY(mMutex); std::deque<TimePoint> mPastExpectedPresentTimes GUARDED_BY(mMutex); + + TimePoint mLastMissedVsync GUARDED_BY(mMutex); }; } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h index 1ed863cf7d..417163f4e1 100644 --- a/services/surfaceflinger/Scheduler/VSyncTracker.h +++ b/services/surfaceflinger/Scheduler/VSyncTracker.h @@ -57,9 +57,13 @@ public: * is updated. * * \param [in] timePoint The point in time after which to estimate a vsync event. + * \param [in] lastVsyncOpt The last vsync time used by the client. If provided, the tracker + * should use that as a reference point when generating the new vsync + * and avoid crossing the minimal frame period of a VRR display. * \return A prediction of the timestamp of a vsync event. */ - virtual nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const = 0; + virtual nsecs_t nextAnticipatedVSyncTimeFrom( + nsecs_t timePoint, std::optional<nsecs_t> lastVsyncOpt = {}) const = 0; /* * The current period of the vsync signal. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2769e5dfc2..2503efcc07 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -551,6 +551,12 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, true); mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled || base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); + + // These are set by the HWC implementation to indicate that they will use the workarounds. + mIsHotplugErrViaNegVsync = + base::GetBoolProperty("debug.sf.hwc_hotplug_error_via_neg_vsync"s, false); + + mIsHdcpViaNegVsync = base::GetBoolProperty("debug.sf.hwc_hdcp_via_neg_vsync"s, false); } LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { @@ -2130,15 +2136,28 @@ nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const { void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp, std::optional<hal::VsyncPeriodNanos> vsyncPeriod) { - if (FlagManager::getInstance().connected_display()) { + if (FlagManager::getInstance().connected_display() && timestamp < 0 && + vsyncPeriod.has_value()) { // use ~0 instead of -1 as AidlComposerHal.cpp passes the param as unsigned int32 - if (mIsHotplugErrViaNegVsync && timestamp < 0 && vsyncPeriod.has_value() && - vsyncPeriod.value() == ~0) { - int hotplugErrorCode = static_cast<int32_t>(-timestamp); - ALOGD("SurfaceFlinger got hotplugErrorCode=%d", hotplugErrorCode); + if (mIsHotplugErrViaNegVsync && vsyncPeriod.value() == ~0) { + const int32_t hotplugErrorCode = static_cast<int32_t>(-timestamp); + ALOGD("SurfaceFlinger got hotplugErrorCode=%d for display %" PRIu64, hotplugErrorCode, + hwcDisplayId); mScheduler->onHotplugConnectionError(mAppConnectionHandle, hotplugErrorCode); return; } + + if (mIsHdcpViaNegVsync && vsyncPeriod.value() == ~1) { + const int32_t value = static_cast<int32_t>(-timestamp); + // one byte is good enough to encode android.hardware.drm.HdcpLevel + const int32_t maxLevel = (value >> 8) & 0xFF; + const int32_t connectedLevel = value & 0xFF; + ALOGD("SurfaceFlinger got HDCP level changed: connected=%d, max=%d for " + "display=%" PRIu64, + connectedLevel, maxLevel, hwcDisplayId); + updateHdcpLevels(hwcDisplayId, connectedLevel, maxLevel); + return; + } } ATRACE_NAME(vsyncPeriod @@ -2372,11 +2391,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, mLegacyLayers[layer->sequence] = layer; } } - if (mLayerLifecycleManager.getGlobalChanges().test(Changes::Hierarchy)) { - ATRACE_NAME("LayerHierarchyBuilder:update"); - mLayerHierarchyBuilder.update(mLayerLifecycleManager.getLayers(), - mLayerLifecycleManager.getDestroyedLayers()); - } + mLayerHierarchyBuilder.update(mLayerLifecycleManager); } bool mustComposite = false; @@ -3432,9 +3447,10 @@ const char* SurfaceFlinger::processHotplug(PhysicalDisplayId displayId, } const sp<IBinder> token = sp<BBinder>::make(); + const ui::DisplayConnectionType connectionType = + getHwComposer().getDisplayConnectionType(displayId); - mPhysicalDisplays.try_emplace(displayId, token, displayId, - getHwComposer().getDisplayConnectionType(displayId), + mPhysicalDisplays.try_emplace(displayId, token, displayId, connectionType, std::move(displayModes), std::move(colorModes), std::move(info.deviceProductInfo)); @@ -3442,7 +3458,7 @@ const char* SurfaceFlinger::processHotplug(PhysicalDisplayId displayId, state.physical = {.id = displayId, .hwcDisplayId = hwcDisplayId, .activeMode = std::move(activeMode)}; - state.isSecure = true; // All physical displays are currently considered secure. + state.isSecure = connectionType == ui::DisplayConnectionType::Internal; state.isProtected = true; state.displayName = std::move(info.name); @@ -4126,7 +4142,7 @@ void SurfaceFlinger::onVsyncGenerated(TimePoint expectedPresentTime, const auto notifyExpectedPresentConfig = modePtr->getVrrConfig()->notifyExpectedPresentConfig; if (!notifyExpectedPresentConfig) return std::nullopt; - return Period::fromNs(notifyExpectedPresentConfig->notifyExpectedPresentTimeoutNs); + return Period::fromNs(notifyExpectedPresentConfig->timeoutNs); }(); notifyExpectedPresentIfRequired(modePtr->getPhysicalDisplayId(), vsyncPeriod, @@ -4248,9 +4264,6 @@ void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) { sp<RegionSamplingThread>::make(*this, RegionSamplingThread::EnvironmentTimingTunables()); mFpsReporter = sp<FpsReporter>::make(*mFrameTimeline, *this); - - mIsHotplugErrViaNegVsync = - base::GetBoolProperty("debug.sf.hwc_hotplug_error_via_neg_vsync"s, false); } void SurfaceFlinger::updatePhaseConfiguration(Fps refreshRate) { @@ -8752,6 +8765,40 @@ status_t SurfaceFlinger::getStalledTransactionInfo( return NO_ERROR; } +void SurfaceFlinger::updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t connectedLevel, + int32_t maxLevel) { + if (!FlagManager::getInstance().connected_display()) { + return; + } + + Mutex::Autolock lock(mStateLock); + + const auto idOpt = getHwComposer().toPhysicalDisplayId(hwcDisplayId); + if (!idOpt) { + ALOGE("No display found for HDCP level changed event: connected=%d, max=%d for " + "display=%" PRIu64, + connectedLevel, maxLevel, hwcDisplayId); + return; + } + + const bool isInternalDisplay = + mPhysicalDisplays.get(*idOpt).transform(&PhysicalDisplay::isInternal).value_or(false); + if (isInternalDisplay) { + ALOGW("Unexpected HDCP level changed for internal display: connected=%d, max=%d for " + "display=%" PRIu64, + connectedLevel, maxLevel, hwcDisplayId); + return; + } + + static_cast<void>(mScheduler->schedule([this, displayId = *idOpt, connectedLevel, maxLevel]() { + if (const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayId))) { + Mutex::Autolock lock(mStateLock); + display->setSecure(connectedLevel >= 2 /* HDCP_V1 */); + } + mScheduler->onHdcpLevelsChanged(mAppConnectionHandle, displayId, connectedLevel, maxLevel); + })); +} + std::shared_ptr<renderengine::ExternalTexture> SurfaceFlinger::getExternalTextureFromBufferData( BufferData& bufferData, const char* layerName, uint64_t transactionId) { if (bufferData.buffer && diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6b4440193b..72003cd65e 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -654,6 +654,8 @@ private: status_t getStalledTransactionInfo( int pid, std::optional<TransactionHandler::StalledTransactionInfo>& result); + void updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t connectedLevel, int32_t maxLevel); + // Implements IBinder::DeathRecipient. void binderDied(const wp<IBinder>& who) override; @@ -1276,6 +1278,7 @@ private: hal::Connection connection = hal::Connection::INVALID; }; + bool mIsHdcpViaNegVsync = false; bool mIsHotplugErrViaNegVsync = false; std::mutex mHotplugMutex; @@ -1469,7 +1472,7 @@ private: bool mLegacyFrontEndEnabled = true; frontend::LayerLifecycleManager mLayerLifecycleManager; - frontend::LayerHierarchyBuilder mLayerHierarchyBuilder{{}}; + frontend::LayerHierarchyBuilder mLayerHierarchyBuilder; frontend::LayerSnapshotBuilder mLayerSnapshotBuilder; std::vector<std::pair<uint32_t, std::string>> mDestroyedHandles; diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h index ddbf3e4873..6a66fff75f 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.h +++ b/services/surfaceflinger/Tracing/TransactionTracing.h @@ -218,6 +218,13 @@ class TransactionTraceWriter : public Singleton<TransactionTraceWriter> { friend class Singleton<TransactionTracing>; std::function<void(const std::string& prefix, bool overwrite)> mWriterFunction = [](const std::string&, bool) {}; + std::atomic<bool> mEnabled{true}; + + void doInvoke(const std::string& filename, bool overwrite) { + if (mEnabled) { + mWriterFunction(filename, overwrite); + } + }; public: void setWriterFunction( @@ -225,12 +232,15 @@ public: mWriterFunction = std::move(function); } void invoke(const std::string& prefix, bool overwrite) { - mWriterFunction(TransactionTracing::getFilePath(prefix), overwrite); + doInvoke(TransactionTracing::getFilePath(prefix), overwrite); } /* pass in a complete file path for testing */ void invokeForTest(const std::string& filename, bool overwrite) { - mWriterFunction(filename, overwrite); + doInvoke(filename, overwrite); } + /* hacky way to avoid generating traces when converting transaction trace to layers trace. */ + void disable() { mEnabled.store(false); } + void enable() { mEnabled.store(true); } }; } // namespace android diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp index c2d1954ee5..617ea2c566 100644 --- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp +++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp @@ -40,9 +40,24 @@ namespace android { using namespace ftl::flag_operators; +namespace { +class ScopedTraceDisabler { +public: + ScopedTraceDisabler() { TransactionTraceWriter::getInstance().disable(); } + ~ScopedTraceDisabler() { TransactionTraceWriter::getInstance().enable(); } +}; +} // namespace + bool LayerTraceGenerator::generate(const perfetto::protos::TransactionTraceFile& traceFile, std::uint32_t traceFlags, LayerTracing& layerTracing, bool onlyLastEntry) { + // We are generating the layers trace by replaying back a set of transactions. If the + // transactions have unexpected states, we may generate a transaction trace to debug + // the unexpected state. This is silly. So we disable it by poking the + // TransactionTraceWriter. This is really a hack since we should manage our depenecies a + // little better. + ScopedTraceDisabler fatalErrorTraceDisabler; + if (traceFile.entry_size() == 0) { ALOGD("Trace file is empty"); return false; @@ -52,7 +67,7 @@ bool LayerTraceGenerator::generate(const perfetto::protos::TransactionTraceFile& // frontend frontend::LayerLifecycleManager lifecycleManager; - frontend::LayerHierarchyBuilder hierarchyBuilder{{}}; + frontend::LayerHierarchyBuilder hierarchyBuilder; frontend::LayerSnapshotBuilder snapshotBuilder; ui::DisplayMap<ui::LayerStack, frontend::DisplayInfo> displayInfos; @@ -119,12 +134,10 @@ bool LayerTraceGenerator::generate(const perfetto::protos::TransactionTraceFile& lifecycleManager.applyTransactions(transactions, /*ignoreUnknownHandles=*/true); lifecycleManager.onHandlesDestroyed(destroyedHandles, /*ignoreUnknownHandles=*/true); - if (lifecycleManager.getGlobalChanges().test( - frontend::RequestedLayerState::Changes::Hierarchy)) { - hierarchyBuilder.update(lifecycleManager.getLayers(), - lifecycleManager.getDestroyedLayers()); - } + // update hierarchy + hierarchyBuilder.update(lifecycleManager); + // update snapshots frontend::LayerSnapshotBuilder::Args args{.root = hierarchyBuilder.getHierarchy(), .layerLifecycleManager = lifecycleManager, .displays = displayInfos, diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp index cb1faee6b9..a27e10033d 100644 --- a/services/surfaceflinger/common/FlagManager.cpp +++ b/services/surfaceflinger/common/FlagManager.cpp @@ -122,7 +122,7 @@ void FlagManager::dump(std::string& result) const { DUMP_READ_ONLY_FLAG(multithreaded_present); DUMP_READ_ONLY_FLAG(add_sf_skipped_frames_to_trace); DUMP_READ_ONLY_FLAG(use_known_refresh_rate_for_fps_consistency); - DUMP_READ_ONLY_FLAG(cache_if_source_crop_layer_only_moved); + DUMP_READ_ONLY_FLAG(cache_when_source_crop_layer_only_moved); DUMP_READ_ONLY_FLAG(enable_fro_dependent_features); DUMP_READ_ONLY_FLAG(display_protected); DUMP_READ_ONLY_FLAG(fp16_client_target); @@ -195,7 +195,7 @@ FLAG_MANAGER_READ_ONLY_FLAG(hdcp_level_hal, "") FLAG_MANAGER_READ_ONLY_FLAG(multithreaded_present, "debug.sf.multithreaded_present") FLAG_MANAGER_READ_ONLY_FLAG(add_sf_skipped_frames_to_trace, "") FLAG_MANAGER_READ_ONLY_FLAG(use_known_refresh_rate_for_fps_consistency, "") -FLAG_MANAGER_READ_ONLY_FLAG(cache_if_source_crop_layer_only_moved, +FLAG_MANAGER_READ_ONLY_FLAG(cache_when_source_crop_layer_only_moved, "debug.sf.cache_source_crop_only_moved") FLAG_MANAGER_READ_ONLY_FLAG(enable_fro_dependent_features, "") FLAG_MANAGER_READ_ONLY_FLAG(display_protected, "") diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h index 2e1d6aee4d..2f2895c82e 100644 --- a/services/surfaceflinger/common/include/common/FlagManager.h +++ b/services/surfaceflinger/common/include/common/FlagManager.h @@ -61,7 +61,7 @@ public: bool multithreaded_present() const; bool add_sf_skipped_frames_to_trace() const; bool use_known_refresh_rate_for_fps_consistency() const; - bool cache_if_source_crop_layer_only_moved() const; + bool cache_when_source_crop_layer_only_moved() const; bool enable_fro_dependent_features() const; bool display_protected() const; bool fp16_client_target() const; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp index b690d8d98e..649ad252d8 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp @@ -134,13 +134,13 @@ void SchedulerFuzzer::fuzzCallbackToken(scheduler::VSyncDispatchTimerQueue* disp dispatch->schedule(tmp, {.workDuration = mFdp.ConsumeIntegral<nsecs_t>(), .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(), - .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()}); + .lastVsync = mFdp.ConsumeIntegral<nsecs_t>()}); }, "o.o"); dispatch->schedule(tmp, {.workDuration = mFdp.ConsumeIntegral<nsecs_t>(), .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(), - .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()}); + .lastVsync = mFdp.ConsumeIntegral<nsecs_t>()}); dispatch->unregisterCallback(tmp); dispatch->cancel(tmp); } @@ -162,20 +162,20 @@ void SchedulerFuzzer::fuzzVSyncDispatchTimerQueue() { entry.update(*stubTracker, 0); entry.schedule({.workDuration = mFdp.ConsumeIntegral<nsecs_t>(), .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(), - .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()}, + .lastVsync = mFdp.ConsumeIntegral<nsecs_t>()}, *stubTracker, 0); entry.disarm(); entry.ensureNotRunning(); entry.schedule({.workDuration = mFdp.ConsumeIntegral<nsecs_t>(), .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(), - .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()}, + .lastVsync = mFdp.ConsumeIntegral<nsecs_t>()}, *stubTracker, 0); auto const wakeup = entry.wakeupTime(); auto const ready = entry.readyTime(); entry.callback(entry.executing(), *wakeup, *ready); entry.addPendingWorkloadUpdate({.workDuration = mFdp.ConsumeIntegral<nsecs_t>(), .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(), - .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()}); + .lastVsync = mFdp.ConsumeIntegral<nsecs_t>()}); dump<scheduler::VSyncDispatchTimerQueueEntry>(&entry, &mFdp); } diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h index fa307e9bb4..114f3b0e7a 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h @@ -86,7 +86,10 @@ public: bool addVsyncTimestamp(nsecs_t /* timestamp */) override { return true; } - nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t /* timePoint */) const override { return 1; } + nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t /* timePoint */, + std::optional<nsecs_t>) const override { + return 1; + } nsecs_t currentPeriod() const override { return 1; } Period minFramePeriod() const override { return Period::fromNs(currentPeriod()); } diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig index 1a28b81483..b65a2b3814 100644 --- a/services/surfaceflinger/surfaceflinger_flags.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags.aconfig @@ -100,8 +100,18 @@ flag { bug: "299201319" } -flag { - name: "cache_if_source_crop_layer_only_moved" +# This flag is broken. +# See alternative one: cache_when_source_crop_layer_only_moved +# flag { +# name: "cache_if_source_crop_layer_only_moved" +# namespace: "core_graphics" +# description: "do not flatten layers if source crop is only moved" +# bug: "305718400" +# is_fixed_read_only: true +# } + +flag { + name: "cache_when_source_crop_layer_only_moved" namespace: "core_graphics" description: "do not flatten layers if source crop is only moved" bug: "305718400" diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index ee12276994..6671414ba6 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -481,14 +481,17 @@ constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY = constexpr int PHYSICAL_DISPLAY_FLAGS = 0x1; -template <typename PhysicalDisplay, int width, int height> +template <typename PhysicalDisplay, int width, int height, + Secure secure = (PhysicalDisplay::CONNECTION_TYPE == ui::DisplayConnectionType::Internal) + ? Secure::TRUE + : Secure::FALSE> struct PhysicalDisplayVariant - : DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, Async::FALSE, - Secure::TRUE, PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY, + : DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, Async::FALSE, secure, + PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY, PHYSICAL_DISPLAY_FLAGS>, HwcDisplayVariant<PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL, DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, - Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY, + Async::FALSE, secure, PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY, PHYSICAL_DISPLAY_FLAGS>, PhysicalDisplay> {}; @@ -515,6 +518,7 @@ struct SecondaryDisplay { }; struct TertiaryDisplay { + static constexpr auto CONNECTION_TYPE = ui::DisplayConnectionType::External; static constexpr Primary PRIMARY = Primary::FALSE; static constexpr uint8_t PORT = 253; static constexpr HWDisplayId HWC_DISPLAY_ID = 1003; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 8891c06c75..4e8a609be6 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -471,7 +471,7 @@ TEST_F(EventThreadTest, getLatestVsyncEventData) { mock::VSyncTracker& mockTracker = *static_cast<mock::VSyncTracker*>(&mVsyncSchedule->getTracker()); - EXPECT_CALL(mockTracker, nextAnticipatedVSyncTimeFrom(_)) + EXPECT_CALL(mockTracker, nextAnticipatedVSyncTimeFrom(_, _)) .WillOnce(Return(preferredExpectedPresentationTime)); VsyncEventData vsyncEventData = mThread->getLatestVsyncEventData(mConnection); diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index 6edecff6a6..a5c0657868 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -21,6 +21,7 @@ #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" +#include <optional> #include <vector> // StrictMock<T> derives from T and is not marked final, so the destructor of T is expected to be @@ -82,6 +83,8 @@ struct HWComposerTest : testing::Test { EXPECT_CALL(*mHal, setVsyncEnabled(hwcDisplayId, Hwc2::IComposerClient::Vsync::DISABLE)); EXPECT_CALL(*mHal, onHotplugConnect(hwcDisplayId)); } + + void setVrrTimeoutHint(bool status) { mHwc.mEnableVrrTimeout = status; } }; TEST_F(HWComposerTest, isHeadless) { @@ -323,6 +326,7 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_ON) { EXPECT_TRUE(mHwc.getModes(info->id, kMaxFrameIntervalNs).empty()); } { + setVrrTimeoutHint(true); constexpr int32_t kWidth = 480; constexpr int32_t kHeight = 720; constexpr int32_t kConfigGroup = 1; @@ -330,10 +334,8 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_ON) { const hal::VrrConfig vrrConfig = hal::VrrConfig{.minFrameIntervalNs = static_cast<Fps>(120_Hz).getPeriodNsecs(), .notifyExpectedPresentConfig = hal::VrrConfig:: - NotifyExpectedPresentConfig{.notifyExpectedPresentHeadsUpNs = - ms2ns(30), - .notifyExpectedPresentTimeoutNs = - ms2ns(30)}}; + NotifyExpectedPresentConfig{.headsUpNs = ms2ns(30), + .timeoutNs = ms2ns(30)}}; hal::DisplayConfiguration displayConfiguration{.configId = kConfigId, .width = kWidth, .height = kHeight, @@ -363,9 +365,9 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_ON) { displayConfiguration.dpi = {kDpi, kDpi}; EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _, _)) - .WillOnce(DoAll(SetArgPointee<2>(std::vector<hal::DisplayConfiguration>{ - displayConfiguration}), - Return(HalError::NONE))); + .WillRepeatedly(DoAll(SetArgPointee<2>(std::vector<hal::DisplayConfiguration>{ + displayConfiguration}), + Return(HalError::NONE))); modes = mHwc.getModes(info->id, kMaxFrameIntervalNs); EXPECT_EQ(modes.size(), size_t{1}); @@ -377,6 +379,10 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_ON) { EXPECT_EQ(modes.front().vrrConfig, vrrConfig); EXPECT_EQ(modes.front().dpiX, kDpi); EXPECT_EQ(modes.front().dpiY, kDpi); + + setVrrTimeoutHint(false); + modes = mHwc.getModes(info->id, kMaxFrameIntervalNs); + EXPECT_EQ(modes.front().vrrConfig->notifyExpectedPresentConfig, std::nullopt); } } diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp index 95f19406b4..2b333f4b87 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp @@ -45,7 +45,8 @@ protected: // reparenting tests TEST_F(LayerHierarchyTest, addLayer) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); std::vector<uint32_t> expectedTraversalPath = {1, 11, 111, 12, 121, 122, 1221, 13, 2}; EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath); EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expectedTraversalPath); @@ -64,7 +65,8 @@ TEST_F(LayerHierarchyTest, addLayer) { } TEST_F(LayerHierarchyTest, reparentLayer) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentLayer(2, 11); reparentLayer(111, 12); reparentLayer(1221, 1); @@ -79,7 +81,8 @@ TEST_F(LayerHierarchyTest, reparentLayer) { } TEST_F(LayerHierarchyTest, reparentLayerToNull) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentLayer(2, UNASSIGNED_LAYER_ID); reparentLayer(11, UNASSIGNED_LAYER_ID); @@ -96,7 +99,8 @@ TEST_F(LayerHierarchyTest, reparentLayerToNull) { } TEST_F(LayerHierarchyTest, reparentLayerToNullAndDestroyHandles) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentLayer(2, UNASSIGNED_LAYER_ID); reparentLayer(11, UNASSIGNED_LAYER_ID); reparentLayer(1221, UNASSIGNED_LAYER_ID); @@ -115,7 +119,8 @@ TEST_F(LayerHierarchyTest, reparentLayerToNullAndDestroyHandles) { } TEST_F(LayerHierarchyTest, destroyHandleThenDestroyParentLayer) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); destroyLayerHandle(111); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -139,7 +144,8 @@ TEST_F(LayerHierarchyTest, destroyHandleThenDestroyParentLayer) { } TEST_F(LayerHierarchyTest, layerSurvivesTemporaryReparentToNull) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentLayer(11, UNASSIGNED_LAYER_ID); reparentLayer(11, 1); @@ -154,7 +160,8 @@ TEST_F(LayerHierarchyTest, layerSurvivesTemporaryReparentToNull) { // offscreen tests TEST_F(LayerHierarchyTest, layerMovesOnscreen) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentLayer(11, UNASSIGNED_LAYER_ID); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -170,7 +177,8 @@ TEST_F(LayerHierarchyTest, layerMovesOnscreen) { } TEST_F(LayerHierarchyTest, addLayerToOffscreenParent) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentLayer(11, UNASSIGNED_LAYER_ID); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -187,7 +195,8 @@ TEST_F(LayerHierarchyTest, addLayerToOffscreenParent) { // rel-z tests TEST_F(LayerHierarchyTest, setRelativeParent) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentRelativeLayer(11, 2); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -200,7 +209,8 @@ TEST_F(LayerHierarchyTest, setRelativeParent) { } TEST_F(LayerHierarchyTest, reparentFromRelativeParentWithSetLayer) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentRelativeLayer(11, 2); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -216,7 +226,8 @@ TEST_F(LayerHierarchyTest, reparentFromRelativeParentWithSetLayer) { } TEST_F(LayerHierarchyTest, reparentToRelativeParent) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentRelativeLayer(11, 2); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -231,7 +242,8 @@ TEST_F(LayerHierarchyTest, reparentToRelativeParent) { } TEST_F(LayerHierarchyTest, setParentAsRelativeParent) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentLayer(11, 2); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -246,7 +258,8 @@ TEST_F(LayerHierarchyTest, setParentAsRelativeParent) { } TEST_F(LayerHierarchyTest, relativeChildMovesOffscreenIsNotTraversable) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentRelativeLayer(11, 2); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -262,7 +275,8 @@ TEST_F(LayerHierarchyTest, relativeChildMovesOffscreenIsNotTraversable) { } TEST_F(LayerHierarchyTest, reparentRelativeLayer) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentRelativeLayer(11, 2); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -294,7 +308,8 @@ TEST_F(LayerHierarchyTest, reparentRelativeLayer) { // mirror tests TEST_F(LayerHierarchyTest, canTraverseMirrorLayer) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); mirrorLayer(/*layer*/ 14, /*parent*/ 1, /*layerToMirror*/ 11); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -308,7 +323,8 @@ TEST_F(LayerHierarchyTest, canTraverseMirrorLayer) { } TEST_F(LayerHierarchyTest, canMirrorOffscreenLayer) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentLayer(11, UNASSIGNED_LAYER_ID); mirrorLayer(/*layer*/ 14, /*parent*/ 1, /*layerToMirror*/ 11); @@ -324,7 +340,8 @@ TEST_F(LayerHierarchyTest, canMirrorOffscreenLayer) { TEST_F(LayerHierarchyTest, newChildLayerIsUpdatedInMirrorHierarchy) { mirrorLayer(/*layer*/ 14, /*parent*/ 1, /*layerToMirror*/ 11); mLifecycleManager.commitChanges(); - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); createLayer(1111, 111); createLayer(112, 11); @@ -340,7 +357,8 @@ TEST_F(LayerHierarchyTest, newChildLayerIsUpdatedInMirrorHierarchy) { // mirror & relatives tests TEST_F(LayerHierarchyTest, mirrorWithRelativeOutsideMirrorHierarchy) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentRelativeLayer(111, 12); mirrorLayer(/*layer*/ 14, /*parent*/ 1, /*layerToMirror*/ 11); @@ -371,7 +389,8 @@ TEST_F(LayerHierarchyTest, mirrorWithRelativeOutsideMirrorHierarchy) { } TEST_F(LayerHierarchyTest, mirrorWithRelativeInsideMirrorHierarchy) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentRelativeLayer(1221, 12); mirrorLayer(/*layer*/ 14, /*parent*/ 1, /*layerToMirror*/ 12); @@ -401,7 +420,8 @@ TEST_F(LayerHierarchyTest, mirrorWithRelativeInsideMirrorHierarchy) { } TEST_F(LayerHierarchyTest, childMovesOffscreenWhenRelativeParentDies) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentRelativeLayer(11, 2); reparentLayer(2, UNASSIGNED_LAYER_ID); @@ -427,7 +447,8 @@ TEST_F(LayerHierarchyTest, childMovesOffscreenWhenRelativeParentDies) { } TEST_F(LayerHierarchyTest, offscreenLayerCannotBeRelativeToOnscreenLayer) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentRelativeLayer(1221, 2); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -462,7 +483,8 @@ TEST_F(LayerHierarchyTest, offscreenLayerCannotBeRelativeToOnscreenLayer) { } TEST_F(LayerHierarchyTest, backgroundLayersAreBehindParentLayer) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); updateBackgroundColor(1, 0.5); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -485,7 +507,8 @@ TEST_F(LayerHierarchyTest, ParentBecomesTheChild) { createLayer(11, 1); reparentLayer(1, 11); mLifecycleManager.commitChanges(); - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); std::vector<uint32_t> expectedTraversalPath = {}; EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath); @@ -502,17 +525,11 @@ TEST_F(LayerHierarchyTest, RelativeLoops) { createLayer(11, 1); reparentRelativeLayer(11, 2); reparentRelativeLayer(2, 11); - mLifecycleManager.commitChanges(); - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); - - // fix loop - uint32_t invalidRelativeRoot; - bool hasRelZLoop = hierarchyBuilder.getHierarchy().hasRelZLoop(invalidRelativeRoot); - EXPECT_TRUE(hasRelZLoop); - mLifecycleManager.fixRelativeZLoop(invalidRelativeRoot); - hierarchyBuilder.update(mLifecycleManager.getLayers(), mLifecycleManager.getDestroyedLayers()); - EXPECT_EQ(invalidRelativeRoot, 11u); - EXPECT_FALSE(hierarchyBuilder.getHierarchy().hasRelZLoop(invalidRelativeRoot)); + LayerHierarchyBuilder hierarchyBuilder; + // this call is expected to fix the loop! + hierarchyBuilder.update(mLifecycleManager); + uint32_t unused; + EXPECT_FALSE(hierarchyBuilder.getHierarchy().hasRelZLoop(unused)); std::vector<uint32_t> expectedTraversalPath = {1, 11, 2, 2}; EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath); @@ -534,16 +551,11 @@ TEST_F(LayerHierarchyTest, IndirectRelativeLoops) { createLayer(221, 22); reparentRelativeLayer(22, 111); reparentRelativeLayer(11, 221); - mLifecycleManager.commitChanges(); - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); - - // fix loop - uint32_t invalidRelativeRoot; - bool hasRelZLoop = hierarchyBuilder.getHierarchy().hasRelZLoop(invalidRelativeRoot); - EXPECT_TRUE(hasRelZLoop); - mLifecycleManager.fixRelativeZLoop(invalidRelativeRoot); - hierarchyBuilder.update(mLifecycleManager.getLayers(), mLifecycleManager.getDestroyedLayers()); - EXPECT_FALSE(hierarchyBuilder.getHierarchy().hasRelZLoop(invalidRelativeRoot)); + LayerHierarchyBuilder hierarchyBuilder; + // this call is expected to fix the loop! + hierarchyBuilder.update(mLifecycleManager); + uint32_t unused; + EXPECT_FALSE(hierarchyBuilder.getHierarchy().hasRelZLoop(unused)); std::vector<uint32_t> expectedTraversalPath = {1, 11, 111, 22, 221, 2, 21, 22, 221}; EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath); @@ -554,7 +566,8 @@ TEST_F(LayerHierarchyTest, IndirectRelativeLoops) { } TEST_F(LayerHierarchyTest, ReparentRootLayerToNull) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentLayer(1, UNASSIGNED_LAYER_ID); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -568,7 +581,8 @@ TEST_F(LayerHierarchyTest, ReparentRootLayerToNull) { TEST_F(LayerHierarchyTest, AddRemoveLayerInSameTransaction) { // remove default hierarchy mLifecycleManager = LayerLifecycleManager(); - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); createRootLayer(1); destroyLayerHandle(1); UPDATE_AND_VERIFY(hierarchyBuilder); @@ -582,7 +596,8 @@ TEST_F(LayerHierarchyTest, AddRemoveLayerInSameTransaction) { // traversal path test TEST_F(LayerHierarchyTest, traversalPathId) { setZ(122, -1); - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); auto checkTraversalPathIdVisitor = [](const LayerHierarchy& hierarchy, const LayerHierarchy::TraversalPath& traversalPath) -> bool { @@ -605,7 +620,8 @@ TEST_F(LayerHierarchyTest, zorderRespectsLayerSequenceId) { createLayer(53, 5); mLifecycleManager.commitChanges(); - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); UPDATE_AND_VERIFY(hierarchyBuilder); std::vector<uint32_t> expectedTraversalPath = {1, 11, 2, 4, 5, 51, 53}; EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath); @@ -639,7 +655,8 @@ TEST_F(LayerHierarchyTest, zorderRespectsLayerZ) { setZ(13, 1); mLifecycleManager.commitChanges(); - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); UPDATE_AND_VERIFY(hierarchyBuilder); std::vector<uint32_t> expectedTraversalPath = {1, 11, 13, 12}; EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath); @@ -661,7 +678,8 @@ TEST_F(LayerHierarchyTest, zorderRespectsLayerStack) { setLayerStack(2, 10); mLifecycleManager.commitChanges(); - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); UPDATE_AND_VERIFY(hierarchyBuilder); std::vector<uint32_t> expectedTraversalPath = {2, 21, 1, 11}; EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath); @@ -672,7 +690,8 @@ TEST_F(LayerHierarchyTest, zorderRespectsLayerStack) { } TEST_F(LayerHierarchyTest, canMirrorDisplay) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); setFlags(12, layer_state_t::eLayerSkipScreenshot, layer_state_t::eLayerSkipScreenshot); createDisplayMirrorLayer(3, ui::LayerStack::fromValue(0)); setLayerStack(3, 1); @@ -687,7 +706,8 @@ TEST_F(LayerHierarchyTest, canMirrorDisplay) { } TEST_F(LayerHierarchyTest, mirrorNonExistingDisplay) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); setFlags(12, layer_state_t::eLayerSkipScreenshot, layer_state_t::eLayerSkipScreenshot); createDisplayMirrorLayer(3, ui::LayerStack::fromValue(5)); setLayerStack(3, 1); @@ -701,7 +721,8 @@ TEST_F(LayerHierarchyTest, mirrorNonExistingDisplay) { } TEST_F(LayerHierarchyTest, newRootLayerIsMirrored) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); setFlags(12, layer_state_t::eLayerSkipScreenshot, layer_state_t::eLayerSkipScreenshot); createDisplayMirrorLayer(3, ui::LayerStack::fromValue(0)); setLayerStack(3, 1); @@ -719,7 +740,8 @@ TEST_F(LayerHierarchyTest, newRootLayerIsMirrored) { } TEST_F(LayerHierarchyTest, removedRootLayerIsNoLongerMirrored) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); setFlags(12, layer_state_t::eLayerSkipScreenshot, layer_state_t::eLayerSkipScreenshot); createDisplayMirrorLayer(3, ui::LayerStack::fromValue(0)); setLayerStack(3, 1); @@ -737,7 +759,8 @@ TEST_F(LayerHierarchyTest, removedRootLayerIsNoLongerMirrored) { } TEST_F(LayerHierarchyTest, canMirrorDisplayWithMirrors) { - LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder hierarchyBuilder; + hierarchyBuilder.update(mLifecycleManager); reparentLayer(12, UNASSIGNED_LAYER_ID); mirrorLayer(/*layer*/ 14, /*parent*/ 1, /*layerToMirror*/ 11); UPDATE_AND_VERIFY(hierarchyBuilder); diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index 7e9abce690..67e624922c 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -176,14 +176,12 @@ protected: void destroyLayerHandle(uint32_t id) { mLifecycleManager.onHandlesDestroyed({{id, "test"}}); } void updateAndVerify(LayerHierarchyBuilder& hierarchyBuilder) { - if (mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)) { - hierarchyBuilder.update(mLifecycleManager.getLayers(), - mLifecycleManager.getDestroyedLayers()); - } + hierarchyBuilder.update(mLifecycleManager); mLifecycleManager.commitChanges(); // rebuild layer hierarchy from scratch and verify that it matches the updated state. - LayerHierarchyBuilder newBuilder(mLifecycleManager.getLayers()); + LayerHierarchyBuilder newBuilder; + newBuilder.update(mLifecycleManager); EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), getTraversalPath(newBuilder.getHierarchy())); EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), @@ -512,10 +510,7 @@ protected: } void update(LayerSnapshotBuilder& snapshotBuilder) { - if (mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)) { - mHierarchyBuilder.update(mLifecycleManager.getLayers(), - mLifecycleManager.getDestroyedLayers()); - } + mHierarchyBuilder.update(mLifecycleManager); LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(), .layerLifecycleManager = mLifecycleManager, .includeMetadata = false, @@ -530,7 +525,7 @@ protected: mLifecycleManager.commitChanges(); } - LayerHierarchyBuilder mHierarchyBuilder{{}}; + LayerHierarchyBuilder mHierarchyBuilder; DisplayInfos mFrontEndDisplayInfos; bool mHasDisplayChanges = false; diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp index 787fa1c5e4..e9d231956f 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp @@ -56,7 +56,7 @@ protected: LayerHistoryIntegrationTest() : LayerSnapshotTestBase() { mFlinger.resetScheduler(mScheduler); mLifecycleManager = {}; - mHierarchyBuilder = {{}}; + mHierarchyBuilder = {}; } void updateLayerSnapshotsAndLayerHistory(nsecs_t now) { diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 50cd784725..ba32c68b61 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -58,8 +58,7 @@ protected: void update(LayerSnapshotBuilder& actualBuilder, LayerSnapshotBuilder::Args& args) { if (mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)) { - mHierarchyBuilder.update(mLifecycleManager.getLayers(), - mLifecycleManager.getDestroyedLayers()); + mHierarchyBuilder.update(mLifecycleManager); } args.root = mHierarchyBuilder.getHierarchy(); actualBuilder.update(args); diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp index 9aa089f900..e9c4d801a9 100644 --- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp @@ -91,7 +91,7 @@ namespace { TEST_F(MessageQueueTest, commit) { const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(), .readyDuration = 0, - .earliestVsync = 0}; + .lastVsync = 0}; EXPECT_FALSE(mEventQueue.getScheduledFrameTime()); EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); @@ -105,7 +105,7 @@ TEST_F(MessageQueueTest, commitTwice) { InSequence s; const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(), .readyDuration = 0, - .earliestVsync = 0}; + .lastVsync = 0}; EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); @@ -124,7 +124,7 @@ TEST_F(MessageQueueTest, commitTwiceWithCallback) { InSequence s; const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(), .readyDuration = 0, - .earliestVsync = 0}; + .lastVsync = 0}; EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); @@ -151,7 +151,7 @@ TEST_F(MessageQueueTest, commitTwiceWithCallback) { const auto timingAfterCallback = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(), .readyDuration = 0, - .earliestVsync = kPresentTime.ns()}; + .lastVsync = kPresentTime.ns()}; EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback)).WillOnce(Return(0)); EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); @@ -163,7 +163,7 @@ TEST_F(MessageQueueTest, commitWithDurationChange) { const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDifferentDuration.ns(), .readyDuration = 0, - .earliestVsync = 0}; + .lastVsync = 0}; EXPECT_CALL(*mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(0)); EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame()); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index e515895a1a..7fdca716fb 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -98,7 +98,7 @@ protected: mock::VsyncTrackerCallback mVsyncTrackerCallback; TestableScheduler* mScheduler = new TestableScheduler{mSelector, mSchedulerCallback, mVsyncTrackerCallback}; - surfaceflinger::frontend::LayerHierarchyBuilder mLayerHierarchyBuilder{{}}; + surfaceflinger::frontend::LayerHierarchyBuilder mLayerHierarchyBuilder; ConnectionHandle mConnectionHandle; MockEventThread* mEventThread; @@ -584,17 +584,17 @@ TEST_F(SchedulerTest, nextFrameIntervalTest) { scheduler.setRenderRate(kMode->getPhysicalDisplayId(), frameRate); vrrTracker->addVsyncTimestamp(0); - // Next frame at refresh rate as no previous frame - EXPECT_EQ(refreshRate, - scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), TimePoint::fromNs(0))); - EXPECT_EQ(Fps::fromPeriodNsecs(1000), scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), - TimePoint::fromNs(500))); + TimePoint::fromNs(1000))); EXPECT_EQ(Fps::fromPeriodNsecs(1000), scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), - TimePoint::fromNs(1500))); + TimePoint::fromNs(2000))); + // Not crossing the min frame period + EXPECT_EQ(Fps::fromPeriodNsecs(1500), + scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), + TimePoint::fromNs(2500))); // Change render rate frameRate = Fps::fromPeriodNsecs(2000); vrrSelectorPtr->setActiveMode(kMode->getId(), frameRate); @@ -602,10 +602,10 @@ TEST_F(SchedulerTest, nextFrameIntervalTest) { EXPECT_EQ(Fps::fromPeriodNsecs(2000), scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), - TimePoint::fromNs(2500))); + TimePoint::fromNs(2000))); EXPECT_EQ(Fps::fromPeriodNsecs(2000), scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), - TimePoint::fromNs(4500))); + TimePoint::fromNs(4000))); } TEST_F(SchedulerTest, resyncAllToHardwareVsync) FTL_FAKE_GUARD(kMainThreadContext) { diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index 7ad97a2133..8b16a8a480 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -53,7 +53,7 @@ public: auto vsyncController = std::make_unique<mock::VsyncController>(); auto vsyncTracker = std::make_shared<mock::VSyncTracker>(); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_, _)).WillRepeatedly(Return(0)); EXPECT_CALL(*vsyncTracker, currentPeriod()) .WillRepeatedly(Return( TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); @@ -138,14 +138,14 @@ void DisplayModeSwitchingTest::setupScheduler( auto vsyncController = std::make_unique<mock::VsyncController>(); auto vsyncTracker = std::make_shared<mock::VSyncTracker>(); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_, _)).WillRepeatedly(Return(0)); EXPECT_CALL(*vsyncTracker, currentPeriod()) .WillRepeatedly( Return(TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); EXPECT_CALL(*vsyncTracker, minFramePeriod()) .WillRepeatedly(Return(Period::fromNs( TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD))); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_, _)).WillRepeatedly(Return(0)); mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), std::move(sfEventThread), std::move(selectorPtr), diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_InitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_InitializeDisplaysTest.cpp index fc5f2b0b90..1583f64c0a 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_InitializeDisplaysTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_InitializeDisplaysTest.cpp @@ -46,7 +46,7 @@ TEST_F(InitializeDisplaysTest, commitsPrimaryDisplay) { EXPECT_CALL(static_cast<mock::VSyncTracker&>( mFlinger.scheduler()->getVsyncSchedule()->getTracker()), - nextAnticipatedVSyncTimeFrom(_)) + nextAnticipatedVSyncTimeFrom(_, _)) .WillRepeatedly(Return(0)); // -------------------------------------------------------------------- diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 22cb24bb6f..27030d1027 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -303,13 +303,13 @@ public: auto vsyncController = makeMock<mock::VsyncController>(options.useNiceMock); auto vsyncTracker = makeSharedMock<mock::VSyncTracker>(options.useNiceMock); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_, _)).WillRepeatedly(Return(0)); EXPECT_CALL(*vsyncTracker, currentPeriod()) .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); EXPECT_CALL(*vsyncTracker, minFramePeriod()) .WillRepeatedly( Return(Period::fromNs(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD))); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_, _)).WillRepeatedly(Return(0)); setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), std::move(sfEventThread), DefaultDisplayMode{options.displayId}, SchedulerCallbackImpl::kNoOp, VsyncTrackerCallbackImpl::kNoOp, diff --git a/services/surfaceflinger/tests/unittests/TransactionTraceWriterTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTraceWriterTest.cpp index 4a83d445fc..d071ce985f 100644 --- a/services/surfaceflinger/tests/unittests/TransactionTraceWriterTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionTraceWriterTest.cpp @@ -105,4 +105,16 @@ TEST_F(TransactionTraceWriterTest, overwriteOldFile) { verifyTraceFile(); } +// Check we cannot write to file if the trace write is disabled. +TEST_F(TransactionTraceWriterTest, canDisableTraceWriter) { + TransactionTraceWriter::getInstance().disable(); + TransactionTraceWriter::getInstance().invokeForTest(mFilename, /* overwrite */ true); + EXPECT_NE(access(mFilename.c_str(), F_OK), 0); + + TransactionTraceWriter::getInstance().enable(); + TransactionTraceWriter::getInstance().invokeForTest(mFilename, /* overwrite */ true); + EXPECT_EQ(access(mFilename.c_str(), F_OK), 0); + verifyTraceFile(); +} + } // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp index 6a5635305a..d891008683 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp @@ -64,7 +64,7 @@ class FixedRateIdealStubTracker : public StubTracker { public: FixedRateIdealStubTracker() : StubTracker{toNs(3ms)} {} - nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final { + nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint, std::optional<nsecs_t>) const final { auto const floor = timePoint % mPeriod; if (floor == 0) { return timePoint; @@ -77,7 +77,7 @@ class VRRStubTracker : public StubTracker { public: VRRStubTracker(nsecs_t period) : StubTracker(period) {} - nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t time_point) const final { + nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t time_point, std::optional<nsecs_t>) const final { std::lock_guard lock(mMutex); auto const normalized_to_base = time_point - mBase; auto const floor = (normalized_to_base) % mPeriod; @@ -117,7 +117,7 @@ public: mCallback.schedule( {.workDuration = mWorkload, .readyDuration = mReadyDuration, - .earliestVsync = systemTime(SYSTEM_TIME_MONOTONIC) + mWorkload + mReadyDuration}); + .lastVsync = systemTime(SYSTEM_TIME_MONOTONIC) + mWorkload + mReadyDuration}); for (auto i = 0u; i < iterations - 1; i++) { std::unique_lock lock(mMutex); @@ -130,7 +130,7 @@ public: mCallback.schedule({.workDuration = mWorkload, .readyDuration = mReadyDuration, - .earliestVsync = last + mWorkload + mReadyDuration}); + .lastVsync = last + mWorkload + mReadyDuration}); } // wait for the last callback. diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index 2047018a15..4bf58de05c 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -46,14 +46,14 @@ using namespace com::android::graphics::surfaceflinger; class MockVSyncTracker : public mock::VSyncTracker { public: MockVSyncTracker(nsecs_t period) : mPeriod{period} { - ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_)) + ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_, _)) .WillByDefault(Invoke(this, &MockVSyncTracker::nextVSyncTime)); ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true)); ON_CALL(*this, currentPeriod()) .WillByDefault(Invoke(this, &MockVSyncTracker::getCurrentPeriod)); } - nsecs_t nextVSyncTime(nsecs_t timePoint) const { + nsecs_t nextVSyncTime(nsecs_t timePoint, std::optional<nsecs_t>) const { if (timePoint % mPeriod == 0) { return timePoint; } @@ -243,10 +243,9 @@ TEST_F(VSyncDispatchTimerQueueTest, unregistersSetAlarmOnDestruction) { mDispatchGroupThreshold, mVsyncMoveThreshold); CountingCallback cb(mDispatch); - const auto result = mDispatch->schedule(cb, - {.workDuration = 100, - .readyDuration = 0, - .earliestVsync = 1000}); + const auto result = + mDispatch->schedule(cb, + {.workDuration = 100, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(900, *result); } @@ -257,10 +256,9 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFuture) { EXPECT_CALL(mMockClock, alarmAt(_, 900)); CountingCallback cb(mDispatch); - const auto result = mDispatch->schedule(cb, - {.workDuration = 100, - .readyDuration = 0, - .earliestVsync = intended}); + const auto result = + mDispatch->schedule(cb, + {.workDuration = 100, .readyDuration = 0, .lastVsync = intended}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(900, *result); @@ -277,16 +275,14 @@ TEST_F(VSyncDispatchTimerQueueTest, updateAlarmSettingFuture) { EXPECT_CALL(mMockClock, alarmAt(_, 700)).InSequence(seq); CountingCallback cb(mDispatch); - auto result = mDispatch->schedule(cb, - {.workDuration = 100, - .readyDuration = 0, - .earliestVsync = intended}); + auto result = + mDispatch->schedule(cb, + {.workDuration = 100, .readyDuration = 0, .lastVsync = intended}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(900, *result); result = - mDispatch->update(cb, - {.workDuration = 300, .readyDuration = 0, .earliestVsync = intended}); + mDispatch->update(cb, {.workDuration = 300, .readyDuration = 0, .lastVsync = intended}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(700, *result); @@ -303,17 +299,18 @@ TEST_F(VSyncDispatchTimerQueueTest, updateDoesntSchedule) { CountingCallback cb(mDispatch); const auto result = - mDispatch->update(cb, - {.workDuration = 300, .readyDuration = 0, .earliestVsync = intended}); + mDispatch->update(cb, {.workDuration = 300, .readyDuration = 0, .lastVsync = intended}); EXPECT_FALSE(result.has_value()); } TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithAdjustmentToTrueVsync) { - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(1000)).WillOnce(Return(1150)); + EXPECT_CALL(*mStubTracker.get(), + nextAnticipatedVSyncTimeFrom(1000, std::optional<nsecs_t>(mPeriod))) + .WillOnce(Return(1150)); EXPECT_CALL(mMockClock, alarmAt(_, 1050)); CountingCallback cb(mDispatch); - mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod}); + mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod}); advanceToNextCallback(); ASSERT_THAT(cb.mCalls.size(), Eq(1)); @@ -324,7 +321,8 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingAdjustmentPast) { auto const now = 234; mMockClock.advanceBy(234); auto const workDuration = 10 * mPeriod; - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(now + workDuration)) + EXPECT_CALL(*mStubTracker.get(), + nextAnticipatedVSyncTimeFrom(now + workDuration, std::optional<nsecs_t>(mPeriod))) .WillOnce(Return(mPeriod * 11)); EXPECT_CALL(mMockClock, alarmAt(_, mPeriod)); @@ -332,7 +330,7 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingAdjustmentPast) { const auto result = mDispatch->schedule(cb, {.workDuration = workDuration, .readyDuration = 0, - .earliestVsync = mPeriod}); + .lastVsync = mPeriod}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(mPeriod, *result); } @@ -342,10 +340,9 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) { EXPECT_CALL(mMockClock, alarmCancel()); CountingCallback cb(mDispatch); - const auto result = mDispatch->schedule(cb, - {.workDuration = 100, - .readyDuration = 0, - .earliestVsync = mPeriod}); + const auto result = + mDispatch->schedule(cb, + {.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(mPeriod - 100, *result); EXPECT_EQ(mDispatch->cancel(cb), CancelResult::Cancelled); @@ -356,10 +353,9 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLate) { EXPECT_CALL(mMockClock, alarmCancel()); CountingCallback cb(mDispatch); - const auto result = mDispatch->schedule(cb, - {.workDuration = 100, - .readyDuration = 0, - .earliestVsync = mPeriod}); + const auto result = + mDispatch->schedule(cb, + {.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(mPeriod - 100, *result); mMockClock.advanceBy(950); @@ -371,10 +367,9 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLateWhenRunning) { EXPECT_CALL(mMockClock, alarmCancel()); PausingCallback cb(mDispatch, std::chrono::duration_cast<std::chrono::milliseconds>(1s)); - const auto result = mDispatch->schedule(cb, - {.workDuration = 100, - .readyDuration = 0, - .earliestVsync = mPeriod}); + const auto result = + mDispatch->schedule(cb, + {.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(mPeriod - 100, *result); @@ -393,10 +388,9 @@ TEST_F(VSyncDispatchTimerQueueTest, unregisterSynchronizes) { PausingCallback cb(mDispatch, 50ms); cb.stashResource(resource); - const auto result = mDispatch->schedule(cb, - {.workDuration = 100, - .readyDuration = 0, - .earliestVsync = mPeriod}); + const auto result = + mDispatch->schedule(cb, + {.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(mPeriod - 100, *result); @@ -413,7 +407,8 @@ TEST_F(VSyncDispatchTimerQueueTest, unregisterSynchronizes) { } TEST_F(VSyncDispatchTimerQueueTest, basicTwoAlarmSetting) { - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(1000)) + EXPECT_CALL(*mStubTracker.get(), + nextAnticipatedVSyncTimeFrom(1000, std::optional<nsecs_t>(1000))) .Times(4) .WillOnce(Return(1055)) .WillOnce(Return(1063)) @@ -428,8 +423,8 @@ TEST_F(VSyncDispatchTimerQueueTest, basicTwoAlarmSetting) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch->schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod}); - mDispatch->schedule(cb1, {.workDuration = 250, .readyDuration = 0, .earliestVsync = mPeriod}); + mDispatch->schedule(cb0, {.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod}); + mDispatch->schedule(cb1, {.workDuration = 250, .readyDuration = 0, .lastVsync = mPeriod}); advanceToNextCallback(); advanceToNextCallback(); @@ -441,7 +436,7 @@ TEST_F(VSyncDispatchTimerQueueTest, basicTwoAlarmSetting) { } TEST_F(VSyncDispatchTimerQueueTest, noCloseCallbacksAfterPeriodChange) { - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(_)) + EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(_, _)) .Times(4) .WillOnce(Return(1000)) .WillOnce(Return(2000)) @@ -455,21 +450,21 @@ TEST_F(VSyncDispatchTimerQueueTest, noCloseCallbacksAfterPeriodChange) { CountingCallback cb(mDispatch); - mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 0}); + mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .lastVsync = 0}); advanceToNextCallback(); ASSERT_THAT(cb.mCalls.size(), Eq(1)); EXPECT_THAT(cb.mCalls[0], Eq(1000)); - mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .lastVsync = 1000}); advanceToNextCallback(); ASSERT_THAT(cb.mCalls.size(), Eq(2)); EXPECT_THAT(cb.mCalls[1], Eq(2000)); - mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}); + mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .lastVsync = 2000}); advanceToNextCallback(); @@ -478,7 +473,7 @@ TEST_F(VSyncDispatchTimerQueueTest, noCloseCallbacksAfterPeriodChange) { } TEST_F(VSyncDispatchTimerQueueTest, rearmsFaroutTimeoutWhenCancellingCloseOne) { - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(_)) + EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(_, _)) .Times(4) .WillOnce(Return(10000)) .WillOnce(Return(1000)) @@ -493,9 +488,8 @@ TEST_F(VSyncDispatchTimerQueueTest, rearmsFaroutTimeoutWhenCancellingCloseOne) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch->schedule(cb0, - {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod * 10}); - mDispatch->schedule(cb1, {.workDuration = 250, .readyDuration = 0, .earliestVsync = mPeriod}); + mDispatch->schedule(cb0, {.workDuration = 100, .readyDuration = 0, .lastVsync = mPeriod * 10}); + mDispatch->schedule(cb1, {.workDuration = 250, .readyDuration = 0, .lastVsync = mPeriod}); mDispatch->cancel(cb1); } @@ -507,9 +501,9 @@ TEST_F(VSyncDispatchTimerQueueTest, noUnnecessaryRearmsWhenRescheduling) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch->schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); - mDispatch->schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000}); - mDispatch->schedule(cb1, {.workDuration = 300, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb0, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000}); + mDispatch->schedule(cb1, {.workDuration = 200, .readyDuration = 0, .lastVsync = 1000}); + mDispatch->schedule(cb1, {.workDuration = 300, .readyDuration = 0, .lastVsync = 1000}); advanceToNextCallback(); } @@ -522,9 +516,9 @@ TEST_F(VSyncDispatchTimerQueueTest, necessaryRearmsWhenModifying) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch->schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); - mDispatch->schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000}); - mDispatch->schedule(cb1, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb0, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000}); + mDispatch->schedule(cb1, {.workDuration = 200, .readyDuration = 0, .lastVsync = 1000}); + mDispatch->schedule(cb1, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); advanceToNextCallback(); } @@ -542,10 +536,9 @@ TEST_F(VSyncDispatchTimerQueueTest, modifyIntoGroup) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch->schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); - mDispatch->schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000}); - mDispatch->schedule(cb1, - {.workDuration = closeOffset, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb0, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000}); + mDispatch->schedule(cb1, {.workDuration = 200, .readyDuration = 0, .lastVsync = 1000}); + mDispatch->schedule(cb1, {.workDuration = closeOffset, .readyDuration = 0, .lastVsync = 1000}); advanceToNextCallback(); ASSERT_THAT(cb0.mCalls.size(), Eq(1)); @@ -553,11 +546,9 @@ TEST_F(VSyncDispatchTimerQueueTest, modifyIntoGroup) { ASSERT_THAT(cb1.mCalls.size(), Eq(1)); EXPECT_THAT(cb1.mCalls[0], Eq(mPeriod)); - mDispatch->schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 2000}); + mDispatch->schedule(cb0, {.workDuration = 400, .readyDuration = 0, .lastVsync = 2000}); mDispatch->schedule(cb1, - {.workDuration = notCloseOffset, - .readyDuration = 0, - .earliestVsync = 2000}); + {.workDuration = notCloseOffset, .readyDuration = 0, .lastVsync = 2000}); advanceToNextCallback(); ASSERT_THAT(cb1.mCalls.size(), Eq(2)); EXPECT_THAT(cb1.mCalls[1], Eq(2000)); @@ -577,32 +568,32 @@ TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenEndingAndDoesntCancel) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch->schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); - mDispatch->schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb0, {.workDuration = 100, .readyDuration = 0, .lastVsync = 1000}); + mDispatch->schedule(cb1, {.workDuration = 200, .readyDuration = 0, .lastVsync = 1000}); advanceToNextCallback(); EXPECT_EQ(mDispatch->cancel(cb0), CancelResult::Cancelled); } TEST_F(VSyncDispatchTimerQueueTest, setAlarmCallsAtCorrectTimeWithChangingVsync) { - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(_)) + EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(_, _)) .Times(3) .WillOnce(Return(950)) .WillOnce(Return(1975)) .WillOnce(Return(2950)); CountingCallback cb(mDispatch); - mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 920}); + mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .lastVsync = 920}); mMockClock.advanceBy(850); EXPECT_THAT(cb.mCalls.size(), Eq(1)); - mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1900}); + mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .lastVsync = 1900}); mMockClock.advanceBy(900); EXPECT_THAT(cb.mCalls.size(), Eq(1)); mMockClock.advanceBy(125); EXPECT_THAT(cb.mCalls.size(), Eq(2)); - mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2900}); + mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .lastVsync = 2900}); mMockClock.advanceBy(975); EXPECT_THAT(cb.mCalls.size(), Eq(3)); } @@ -616,13 +607,11 @@ TEST_F(VSyncDispatchTimerQueueTest, callbackReentrancy) { tmp = mDispatch->registerCallback( [&](auto, auto, auto) { mDispatch->schedule(tmp, - {.workDuration = 100, - .readyDuration = 0, - .earliestVsync = 2000}); + {.workDuration = 100, .readyDuration = 0, .lastVsync = 2000}); }, "o.o"); - mDispatch->schedule(tmp, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(tmp, {.workDuration = 100, .readyDuration = 0, .lastVsync = 1000}); advanceToNextCallback(); } @@ -631,30 +620,29 @@ TEST_F(VSyncDispatchTimerQueueTest, callbackReentrantWithPastWakeup) { std::optional<nsecs_t> lastTarget; tmp = mDispatch->registerCallback( [&](auto timestamp, auto, auto) { - auto result = - mDispatch->schedule(tmp, - {.workDuration = 400, - .readyDuration = 0, - .earliestVsync = timestamp - mVsyncMoveThreshold}); + auto result = mDispatch->schedule(tmp, + {.workDuration = 400, + .readyDuration = 0, + .lastVsync = timestamp - mVsyncMoveThreshold}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(mPeriod + timestamp - 400, *result); result = mDispatch->schedule(tmp, {.workDuration = 400, .readyDuration = 0, - .earliestVsync = timestamp}); + .lastVsync = timestamp}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(mPeriod + timestamp - 400, *result); result = mDispatch->schedule(tmp, {.workDuration = 400, .readyDuration = 0, - .earliestVsync = timestamp + mVsyncMoveThreshold}); + .lastVsync = timestamp + mVsyncMoveThreshold}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(mPeriod + timestamp - 400, *result); lastTarget = timestamp; }, "oo"); - mDispatch->schedule(tmp, {.workDuration = 999, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(tmp, {.workDuration = 999, .readyDuration = 0, .lastVsync = 1000}); advanceToNextCallback(); EXPECT_THAT(lastTarget, Eq(1000)); @@ -670,16 +658,16 @@ TEST_F(VSyncDispatchTimerQueueTest, modificationsAroundVsyncTime) { EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq); CountingCallback cb(mDispatch); - mDispatch->schedule(cb, {.workDuration = 0, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 0, .readyDuration = 0, .lastVsync = 1000}); mMockClock.advanceBy(750); - mDispatch->schedule(cb, {.workDuration = 50, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 50, .readyDuration = 0, .lastVsync = 1000}); advanceToNextCallback(); - mDispatch->schedule(cb, {.workDuration = 50, .readyDuration = 0, .earliestVsync = 2000}); + mDispatch->schedule(cb, {.workDuration = 50, .readyDuration = 0, .lastVsync = 2000}); mMockClock.advanceBy(800); - mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}); + mDispatch->schedule(cb, {.workDuration = 100, .readyDuration = 0, .lastVsync = 2000}); } TEST_F(VSyncDispatchTimerQueueTest, lateModifications) { @@ -692,12 +680,12 @@ TEST_F(VSyncDispatchTimerQueueTest, lateModifications) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); - mDispatch->schedule(cb1, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); + mDispatch->schedule(cb1, {.workDuration = 100, .readyDuration = 0, .lastVsync = 1000}); advanceToNextCallback(); - mDispatch->schedule(cb0, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 2000}); - mDispatch->schedule(cb1, {.workDuration = 150, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb0, {.workDuration = 200, .readyDuration = 0, .lastVsync = 2000}); + mDispatch->schedule(cb1, {.workDuration = 150, .readyDuration = 0, .lastVsync = 1000}); advanceToNextCallback(); advanceToNextCallback(); @@ -709,8 +697,8 @@ TEST_F(VSyncDispatchTimerQueueTest, doesntCancelPriorValidTimerForFutureMod) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); - mDispatch->schedule(cb1, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 20000}); + mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); + mDispatch->schedule(cb1, {.workDuration = 500, .readyDuration = 0, .lastVsync = 20000}); } TEST_F(VSyncDispatchTimerQueueTest, setsTimerAfterCancellation) { @@ -720,17 +708,15 @@ TEST_F(VSyncDispatchTimerQueueTest, setsTimerAfterCancellation) { EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq); CountingCallback cb0(mDispatch); - mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); mDispatch->cancel(cb0); - mDispatch->schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb0, {.workDuration = 100, .readyDuration = 0, .lastVsync = 1000}); } TEST_F(VSyncDispatchTimerQueueTest, makingUpIdsError) { VSyncDispatch::CallbackToken token(100); EXPECT_FALSE( - mDispatch - ->schedule(token, - {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}) + mDispatch->schedule(token, {.workDuration = 100, .readyDuration = 0, .lastVsync = 1000}) .has_value()); EXPECT_THAT(mDispatch->cancel(token), Eq(CancelResult::Error)); } @@ -738,12 +724,10 @@ TEST_F(VSyncDispatchTimerQueueTest, makingUpIdsError) { TEST_F(VSyncDispatchTimerQueueTest, canMoveCallbackBackwardsInTime) { CountingCallback cb0(mDispatch); auto result = - mDispatch->schedule(cb0, - {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(500, *result); - result = mDispatch->schedule(cb0, - {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); + result = mDispatch->schedule(cb0, {.workDuration = 100, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(900, *result); } @@ -755,14 +739,12 @@ TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipASchedule EXPECT_CALL(mMockClock, alarmAt(_, 500)); CountingCallback cb(mDispatch); auto result = - mDispatch->schedule(cb, - {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(500, *result); mMockClock.advanceBy(400); - result = mDispatch->schedule(cb, - {.workDuration = 800, .readyDuration = 0, .earliestVsync = 1000}); + result = mDispatch->schedule(cb, {.workDuration = 800, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(1200, *result); @@ -779,14 +761,12 @@ TEST_F(VSyncDispatchTimerQueueTest, movesCallbackBackwardsAndSkipAScheduledTarge EXPECT_CALL(mMockClock, alarmAt(_, 400)).InSequence(seq); CountingCallback cb(mDispatch); auto result = - mDispatch->schedule(cb, - {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(500, *result); mMockClock.advanceBy(400); - result = mDispatch->schedule(cb, - {.workDuration = 800, .readyDuration = 0, .earliestVsync = 1000}); + result = mDispatch->schedule(cb, {.workDuration = 800, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(400, *result); @@ -795,19 +775,18 @@ TEST_F(VSyncDispatchTimerQueueTest, movesCallbackBackwardsAndSkipAScheduledTarge } TEST_F(VSyncDispatchTimerQueueTest, targetOffsetMovingBackALittleCanStillSchedule) { - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(1000)) + EXPECT_CALL(*mStubTracker.get(), + nextAnticipatedVSyncTimeFrom(1000, std::optional<nsecs_t>(1000))) .Times(2) .WillOnce(Return(1000)) .WillOnce(Return(1002)); CountingCallback cb(mDispatch); auto result = - mDispatch->schedule(cb, - {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(500, *result); mMockClock.advanceBy(400); - result = mDispatch->schedule(cb, - {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); + result = mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(602, *result); } @@ -815,13 +794,12 @@ TEST_F(VSyncDispatchTimerQueueTest, targetOffsetMovingBackALittleCanStillSchedul TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) { CountingCallback cb0(mDispatch); auto result = - mDispatch->schedule(cb0, - {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(500, *result); advanceToNextCallback(); - result = mDispatch->schedule(cb0, - {.workDuration = 1100, .readyDuration = 0, .earliestVsync = 2000}); + result = + mDispatch->schedule(cb0, {.workDuration = 1100, .readyDuration = 0, .lastVsync = 2000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(900, *result); } @@ -832,13 +810,12 @@ TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) { EXPECT_CALL(mMockClock, alarmAt(_, 1100)).InSequence(seq); CountingCallback cb0(mDispatch); auto result = - mDispatch->schedule(cb0, - {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb0, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(500, *result); advanceToNextCallback(); - result = mDispatch->schedule(cb0, - {.workDuration = 1900, .readyDuration = 0, .earliestVsync = 2000}); + result = + mDispatch->schedule(cb0, {.workDuration = 1900, .readyDuration = 0, .lastVsync = 2000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(1100, *result); } @@ -850,13 +827,11 @@ TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) CountingCallback cb(mDispatch); auto result = - mDispatch->schedule(cb, - {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(600, *result); - result = mDispatch->schedule(cb, - {.workDuration = 1400, .readyDuration = 0, .earliestVsync = 1000}); + result = mDispatch->schedule(cb, {.workDuration = 1400, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(600, *result); @@ -872,13 +847,11 @@ TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesAffectSchedulingState) { CountingCallback cb(mDispatch); auto result = - mDispatch->schedule(cb, - {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(600, *result); - result = mDispatch->schedule(cb, - {.workDuration = 1400, .readyDuration = 0, .earliestVsync = 1000}); + result = mDispatch->schedule(cb, {.workDuration = 1400, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(0, *result); @@ -892,10 +865,10 @@ TEST_F(VSyncDispatchTimerQueueTest, helperMove) { VSyncCallbackRegistration cb( mDispatch, [](auto, auto, auto) {}, ""); VSyncCallbackRegistration cb1(std::move(cb)); - cb.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); + cb.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 1000}); cb.cancel(); - cb1.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + cb1.schedule({.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); cb1.cancel(); } @@ -908,10 +881,10 @@ TEST_F(VSyncDispatchTimerQueueTest, helperMoveAssign) { VSyncCallbackRegistration cb1( mDispatch, [](auto, auto, auto) {}, ""); cb1 = std::move(cb); - cb.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); + cb.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 1000}); cb.cancel(); - cb1.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + cb1.schedule({.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); cb1.cancel(); } @@ -924,16 +897,14 @@ TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminent CountingCallback cb2(mDispatch); auto result = - mDispatch->schedule(cb1, - {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb1, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(600, *result); mMockClock.setLag(100); mMockClock.advanceBy(620); - result = mDispatch->schedule(cb2, - {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}); + result = mDispatch->schedule(cb2, {.workDuration = 100, .readyDuration = 0, .lastVsync = 2000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(1900, *result); mMockClock.advanceBy(80); @@ -952,16 +923,14 @@ TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminent CountingCallback cb(mDispatch); auto result = - mDispatch->schedule(cb, - {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(600, *result); mMockClock.setLag(100); mMockClock.advanceBy(620); - result = mDispatch->schedule(cb, - {.workDuration = 370, .readyDuration = 0, .earliestVsync = 2000}); + result = mDispatch->schedule(cb, {.workDuration = 370, .readyDuration = 0, .lastVsync = 2000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(1630, *result); mMockClock.advanceBy(80); @@ -978,12 +947,10 @@ TEST_F(VSyncDispatchTimerQueueTest, skipsRearmingWhenNotNextScheduled) { CountingCallback cb2(mDispatch); auto result = - mDispatch->schedule(cb1, - {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb1, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(600, *result); - result = mDispatch->schedule(cb2, - {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}); + result = mDispatch->schedule(cb2, {.workDuration = 100, .readyDuration = 0, .lastVsync = 2000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(1900, *result); @@ -1007,12 +974,10 @@ TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenCancelledAndIsNextScheduled) { CountingCallback cb2(mDispatch); auto result = - mDispatch->schedule(cb1, - {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb1, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(600, *result); - result = mDispatch->schedule(cb2, - {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}); + result = mDispatch->schedule(cb2, {.workDuration = 100, .readyDuration = 0, .lastVsync = 2000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(1900, *result); @@ -1034,21 +999,21 @@ TEST_F(VSyncDispatchTimerQueueTest, laggedTimerGroupsCallbacksWithinLag) { CountingCallback cb2(mDispatch); Sequence seq; - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(1000)) + EXPECT_CALL(*mStubTracker.get(), + nextAnticipatedVSyncTimeFrom(1000, std::optional<nsecs_t>(1000))) .InSequence(seq) .WillOnce(Return(1000)); EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq); - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(1000)) + EXPECT_CALL(*mStubTracker.get(), + nextAnticipatedVSyncTimeFrom(1000, std::optional<nsecs_t>(1000))) .InSequence(seq) .WillOnce(Return(1000)); auto result = - mDispatch->schedule(cb1, - {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb1, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(600, *result); - result = mDispatch->schedule(cb2, - {.workDuration = 390, .readyDuration = 0, .earliestVsync = 1000}); + result = mDispatch->schedule(cb2, {.workDuration = 390, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(610, *result); @@ -1070,10 +1035,9 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithReadyDuration) { EXPECT_CALL(mMockClock, alarmAt(_, 900)); CountingCallback cb(mDispatch); - const auto result = mDispatch->schedule(cb, - {.workDuration = 70, - .readyDuration = 30, - .earliestVsync = intended}); + const auto result = + mDispatch->schedule(cb, + {.workDuration = 70, .readyDuration = 30, .lastVsync = intended}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(900, *result); advanceToNextCallback(); @@ -1094,8 +1058,8 @@ TEST_F(VSyncDispatchTimerQueueTest, updatesVsyncTimeForCloseWakeupTime) { CountingCallback cb(mDispatch); - mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); - mDispatch->schedule(cb, {.workDuration = 1400, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 1400, .readyDuration = 0, .lastVsync = 1000}); advanceToNextCallback(); @@ -1118,8 +1082,8 @@ TEST_F(VSyncDispatchTimerQueueTest, doesNotUpdatesVsyncTimeForCloseWakeupTime) { CountingCallback cb(mDispatch); - mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); - mDispatch->schedule(cb, {.workDuration = 1400, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 1400, .readyDuration = 0, .lastVsync = 1000}); advanceToNextCallback(); @@ -1139,14 +1103,12 @@ TEST_F(VSyncDispatchTimerQueueTest, skipAVsyc) { EXPECT_CALL(mMockClock, alarmAt(_, 500)); CountingCallback cb(mDispatch); auto result = - mDispatch->schedule(cb, - {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(500, *result); mMockClock.advanceBy(300); - result = mDispatch->schedule(cb, - {.workDuration = 800, .readyDuration = 0, .earliestVsync = 1000}); + result = mDispatch->schedule(cb, {.workDuration = 800, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(1200, *result); @@ -1162,14 +1124,12 @@ TEST_F(VSyncDispatchTimerQueueTest, dontskipAVsyc) { EXPECT_CALL(mMockClock, alarmAt(_, 300)).InSequence(seq); CountingCallback cb(mDispatch); auto result = - mDispatch->schedule(cb, - {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 500, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(500, *result); mMockClock.advanceBy(300); - result = mDispatch->schedule(cb, - {.workDuration = 800, .readyDuration = 0, .earliestVsync = 1000}); + result = mDispatch->schedule(cb, {.workDuration = 800, .readyDuration = 0, .lastVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(300, *result); @@ -1204,7 +1164,7 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) { "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); EXPECT_FALSE(entry.wakeupTime()); - EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); auto const wakeup = entry.wakeupTime(); @@ -1219,14 +1179,15 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, stateSchedulingReallyLongWakeupLatency) auto const duration = 500; auto const now = 8750; - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(now + duration)) + EXPECT_CALL(*mStubTracker.get(), + nextAnticipatedVSyncTimeFrom(now + duration, std::optional<nsecs_t>(994))) .Times(1) .WillOnce(Return(10000)); VSyncDispatchTimerQueueEntry entry( "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); EXPECT_FALSE(entry.wakeupTime()); - EXPECT_TRUE(entry.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 994}, + EXPECT_TRUE(entry.schedule({.workDuration = 500, .readyDuration = 0, .lastVsync = 994}, *mStubTracker.get(), now) .has_value()); auto const wakeup = entry.wakeupTime(); @@ -1249,7 +1210,7 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) { }, mVsyncMoveThreshold); - EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); auto const wakeup = entry.wakeupTime(); @@ -1272,7 +1233,7 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) { } TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) { - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(_)) + EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(_, _)) .Times(2) .WillOnce(Return(1000)) .WillOnce(Return(1020)); @@ -1284,7 +1245,7 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) { entry.update(*mStubTracker.get(), 0); EXPECT_FALSE(entry.wakeupTime()); - EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); auto wakeup = entry.wakeupTime(); @@ -1300,7 +1261,7 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) { TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) { VSyncDispatchTimerQueueEntry entry( "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); - EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); entry.update(*mStubTracker.get(), 0); @@ -1313,24 +1274,24 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) { TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) { VSyncDispatchTimerQueueEntry entry( "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); - EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); entry.executing(); // 1000 is executing // had 1000 not been executing, this could have been scheduled for time 800. - EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); EXPECT_THAT(*entry.wakeupTime(), Eq(1800)); EXPECT_THAT(*entry.readyTime(), Eq(2000)); - EXPECT_TRUE(entry.schedule({.workDuration = 50, .readyDuration = 0, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 50, .readyDuration = 0, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); EXPECT_THAT(*entry.wakeupTime(), Eq(1950)); EXPECT_THAT(*entry.readyTime(), Eq(2000)); - EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 1001}, + EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 1001}, *mStubTracker.get(), 0) .has_value()); EXPECT_THAT(*entry.wakeupTime(), Eq(1800)); @@ -1343,23 +1304,25 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); Sequence seq; - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(500)) + EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(500, std::optional<nsecs_t>(500))) .InSequence(seq) .WillOnce(Return(1000)); - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(500)) + EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(500, std::optional<nsecs_t>(500))) .InSequence(seq) .WillOnce(Return(1000)); - EXPECT_CALL(*mStubTracker.get(), nextAnticipatedVSyncTimeFrom(1000 + mVsyncMoveThreshold)) + EXPECT_CALL(*mStubTracker.get(), + nextAnticipatedVSyncTimeFrom(1000 + mVsyncMoveThreshold, + std::optional<nsecs_t>(1000))) .InSequence(seq) .WillOnce(Return(2000)); - EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); entry.executing(); // 1000 is executing - EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); } @@ -1367,16 +1330,16 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) { VSyncDispatchTimerQueueEntry entry( "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); - EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); - EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); - EXPECT_TRUE(entry.schedule({.workDuration = 50, .readyDuration = 0, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 50, .readyDuration = 0, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); - EXPECT_TRUE(entry.schedule({.workDuration = 1200, .readyDuration = 0, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 1200, .readyDuration = 0, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); } @@ -1386,9 +1349,9 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, storesPendingUpdatesUntilUpdate) { VSyncDispatchTimerQueueEntry entry( "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); EXPECT_FALSE(entry.hasPendingWorkloadUpdate()); - entry.addPendingWorkloadUpdate({.workDuration = 100, .readyDuration = 0, .earliestVsync = 400}); + entry.addPendingWorkloadUpdate({.workDuration = 100, .readyDuration = 0, .lastVsync = 400}); entry.addPendingWorkloadUpdate( - {.workDuration = effectualOffset, .readyDuration = 0, .earliestVsync = 400}); + {.workDuration = effectualOffset, .readyDuration = 0, .lastVsync = 400}); EXPECT_TRUE(entry.hasPendingWorkloadUpdate()); entry.update(*mStubTracker.get(), 0); EXPECT_FALSE(entry.hasPendingWorkloadUpdate()); @@ -1410,7 +1373,7 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, runCallbackWithReadyDuration) { }, mVsyncMoveThreshold); - EXPECT_TRUE(entry.schedule({.workDuration = 70, .readyDuration = 30, .earliestVsync = 500}, + EXPECT_TRUE(entry.schedule({.workDuration = 70, .readyDuration = 30, .lastVsync = 500}, *mStubTracker.get(), 0) .has_value()); auto const wakeup = entry.wakeupTime(); diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp index 7a498c9d29..961ba578ca 100644 --- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp @@ -662,7 +662,7 @@ TEST_F(VSyncPredictorTest, vsyncTrackerCallback) { const auto refreshRate = Fps::fromPeriodNsecs(mPeriod); NotifyExpectedPresentConfig notifyExpectedPresentConfig; - notifyExpectedPresentConfig.notifyExpectedPresentTimeoutNs = Period::fromNs(30).ns(); + notifyExpectedPresentConfig.timeoutNs = Period::fromNs(30).ns(); hal::VrrConfig vrrConfig; vrrConfig.notifyExpectedPresentConfig = notifyExpectedPresentConfig; @@ -720,15 +720,17 @@ TEST_F(VSyncPredictorTest, adjustsVrrTimeline) { vrrTracker.setRenderRate(minFrameRate); vrrTracker.addVsyncTimestamp(0); EXPECT_EQ(1000, vrrTracker.nextAnticipatedVSyncTimeFrom(700)); - EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1300)); + EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1000)); vrrTracker.onFrameBegin(TimePoint::fromNs(2000), TimePoint::fromNs(1500)); - EXPECT_EQ(1500, vrrTracker.nextAnticipatedVSyncTimeFrom(1300)); - EXPECT_EQ(2500, vrrTracker.nextAnticipatedVSyncTimeFrom(2300)); - - vrrTracker.onFrameMissed(TimePoint::fromNs(2500)); - EXPECT_EQ(3000, vrrTracker.nextAnticipatedVSyncTimeFrom(2300)); - EXPECT_EQ(4000, vrrTracker.nextAnticipatedVSyncTimeFrom(3300)); + EXPECT_EQ(3500, vrrTracker.nextAnticipatedVSyncTimeFrom(2000, 2000)); + EXPECT_EQ(4500, vrrTracker.nextAnticipatedVSyncTimeFrom(3500, 3500)); + + // Miss when starting 4500 and expect the next vsync will be at 5000 (next one) + vrrTracker.onFrameBegin(TimePoint::fromNs(3500), TimePoint::fromNs(2500)); + vrrTracker.onFrameMissed(TimePoint::fromNs(4500)); + EXPECT_EQ(5000, vrrTracker.nextAnticipatedVSyncTimeFrom(4500, 4500)); + EXPECT_EQ(6000, vrrTracker.nextAnticipatedVSyncTimeFrom(5000, 5000)); } } // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h index a088aabc11..ed1405b058 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h @@ -18,12 +18,21 @@ #include "binder/Status.h" +// FMQ library in IPower does questionable conversions +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" #include <aidl/android/hardware/power/IPower.h> +#pragma clang diagnostic pop + #include <gmock/gmock.h> using aidl::android::hardware::power::Boost; +using aidl::android::hardware::power::ChannelConfig; using aidl::android::hardware::power::IPower; using aidl::android::hardware::power::IPowerHintSession; +using aidl::android::hardware::power::SessionConfig; +using aidl::android::hardware::power::SessionTag; + using aidl::android::hardware::power::Mode; using android::binder::Status; @@ -42,6 +51,14 @@ public: int64_t durationNanos, std::shared_ptr<IPowerHintSession>* session), (override)); MOCK_METHOD(ndk::ScopedAStatus, getHintSessionPreferredRate, (int64_t * rate), (override)); + MOCK_METHOD(ndk::ScopedAStatus, createHintSessionWithConfig, + (int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, + int64_t durationNanos, SessionTag tag, SessionConfig* config, + std::shared_ptr<IPowerHintSession>* _aidl_return), + (override)); + MOCK_METHOD(ndk::ScopedAStatus, getSessionChannel, + (int32_t tgid, int32_t uid, ChannelConfig* _aidl_return), (override)); + MOCK_METHOD(ndk::ScopedAStatus, closeSessionChannel, (int32_t tgid, int32_t uid), (override)); MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t * version), (override)); MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string * hash), (override)); MOCK_METHOD(ndk::SpAIBinder, asBinder, (), (override)); diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h index 364618d61a..27564b26de 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h @@ -18,10 +18,15 @@ #include "binder/Status.h" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" #include <aidl/android/hardware/power/IPower.h> +#pragma clang diagnostic pop + #include <gmock/gmock.h> using aidl::android::hardware::power::IPowerHintSession; +using aidl::android::hardware::power::SessionConfig; using aidl::android::hardware::power::SessionHint; using aidl::android::hardware::power::SessionMode; using android::binder::Status; @@ -47,6 +52,7 @@ public: MOCK_METHOD(ndk::ScopedAStatus, sendHint, (SessionHint), (override)); MOCK_METHOD(ndk::ScopedAStatus, setThreads, (const ::std::vector<int32_t>&), (override)); MOCK_METHOD(ndk::ScopedAStatus, setMode, (SessionMode, bool), (override)); + MOCK_METHOD(ndk::ScopedAStatus, getSessionConfig, (SessionConfig * _aidl_return), (override)); }; } // namespace android::Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h index 68fe3c52d4..b17c8adf6c 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h @@ -19,7 +19,10 @@ #include <gmock/gmock.h> #include <scheduler/Time.h> +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" #include <powermanager/PowerHalController.h> +#pragma clang diagnostic pop namespace android { namespace hardware { diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 866af3bbd0..e2b0ed1df9 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -59,6 +59,9 @@ public: MOCK_METHOD(void, requestLatestConfig, (const sp<android::EventThreadConnection>&)); MOCK_METHOD(void, pauseVsyncCallback, (bool)); MOCK_METHOD(void, onNewVsyncSchedule, (std::shared_ptr<scheduler::VsyncSchedule>), (override)); + MOCK_METHOD(void, onHdcpLevelsChanged, + (PhysicalDisplayId displayId, int32_t connectedLevel, int32_t maxLevel), + (override)); }; } // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h index e588bb9a3f..3870983133 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h +++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h @@ -28,7 +28,8 @@ public: ~VSyncTracker() override; MOCK_METHOD(bool, addVsyncTimestamp, (nsecs_t), (override)); - MOCK_METHOD(nsecs_t, nextAnticipatedVSyncTimeFrom, (nsecs_t), (const, override)); + MOCK_METHOD(nsecs_t, nextAnticipatedVSyncTimeFrom, (nsecs_t, std::optional<nsecs_t>), + (const, override)); MOCK_METHOD(nsecs_t, currentPeriod, (), (const, override)); MOCK_METHOD(Period, minFramePeriod, (), (const, override)); MOCK_METHOD(void, resetModel, (), (override)); |