From 98318de954ba00293cfd179266f09f266dc1c82b Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 19 May 2021 16:45:23 -0500 Subject: Renamed and moved InputWindow and related files In preparation for the hierarchy listener interface, moved the InputWindow structs into libgui and have libinput dependant on libgui. Also renamed InputWindow to exclude Input since it will be used for more generic purposes. Test: Builds and flashes Bug: 188792659 Change-Id: I24262cbc14d409c00273de0024a672394a959e5f --- libs/gui/WindowInfo.cpp | 223 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 libs/gui/WindowInfo.cpp (limited to 'libs/gui/WindowInfo.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp new file mode 100644 index 0000000000..ff0bb8aa55 --- /dev/null +++ b/libs/gui/WindowInfo.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#define LOG_TAG "WindowInfo" +#define LOG_NDEBUG 0 + +#include +#include +#include + +#include + +namespace android::gui { + +// --- WindowInfo --- +void WindowInfo::addTouchableRegion(const Rect& region) { + touchableRegion.orSelf(region); +} + +bool WindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { + return touchableRegion.contains(x, y); +} + +bool WindowInfo::frameContainsPoint(int32_t x, int32_t y) const { + return x >= frameLeft && x < frameRight && y >= frameTop && y < frameBottom; +} + +bool WindowInfo::supportsSplitTouch() const { + return flags.test(Flag::SPLIT_TOUCH); +} + +bool WindowInfo::overlaps(const WindowInfo* other) const { + return frameLeft < other->frameRight && frameRight > other->frameLeft && + frameTop < other->frameBottom && frameBottom > other->frameTop; +} + +bool WindowInfo::operator==(const WindowInfo& info) const { + return info.token == token && info.id == id && info.name == name && info.flags == flags && + info.type == type && info.dispatchingTimeout == dispatchingTimeout && + info.frameLeft == frameLeft && info.frameTop == frameTop && + info.frameRight == frameRight && info.frameBottom == frameBottom && + info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor && + info.transform == transform && info.displayWidth == displayWidth && + info.displayHeight == displayHeight && + info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible && + info.trustedOverlay == trustedOverlay && info.focusable == focusable && + info.touchOcclusionMode == touchOcclusionMode && info.hasWallpaper == hasWallpaper && + info.paused == paused && info.ownerPid == ownerPid && info.ownerUid == ownerUid && + info.packageName == packageName && info.inputFeatures == inputFeatures && + info.displayId == displayId && info.portalToDisplayId == portalToDisplayId && + info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && + info.applicationInfo == applicationInfo; +} + +status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + if (name.empty()) { + parcel->writeInt32(0); + return OK; + } + parcel->writeInt32(1); + + // clang-format off + status_t status = parcel->writeStrongBinder(token) ?: + parcel->writeInt64(dispatchingTimeout.count()) ?: + parcel->writeInt32(id) ?: + parcel->writeUtf8AsUtf16(name) ?: + parcel->writeInt32(flags.get()) ?: + parcel->writeInt32(static_cast>(type)) ?: + parcel->writeInt32(frameLeft) ?: + parcel->writeInt32(frameTop) ?: + parcel->writeInt32(frameRight) ?: + parcel->writeInt32(frameBottom) ?: + parcel->writeInt32(surfaceInset) ?: + parcel->writeFloat(globalScaleFactor) ?: + parcel->writeFloat(alpha) ?: + parcel->writeFloat(transform.dsdx()) ?: + parcel->writeFloat(transform.dtdx()) ?: + parcel->writeFloat(transform.tx()) ?: + parcel->writeFloat(transform.dtdy()) ?: + parcel->writeFloat(transform.dsdy()) ?: + parcel->writeFloat(transform.ty()) ?: + parcel->writeInt32(displayWidth) ?: + parcel->writeInt32(displayHeight) ?: + parcel->writeBool(visible) ?: + parcel->writeBool(focusable) ?: + parcel->writeBool(hasWallpaper) ?: + parcel->writeBool(paused) ?: + parcel->writeBool(trustedOverlay) ?: + parcel->writeInt32(static_cast(touchOcclusionMode)) ?: + parcel->writeInt32(ownerPid) ?: + parcel->writeInt32(ownerUid) ?: + parcel->writeUtf8AsUtf16(packageName) ?: + parcel->writeInt32(inputFeatures.get()) ?: + parcel->writeInt32(displayId) ?: + parcel->writeInt32(portalToDisplayId) ?: + applicationInfo.writeToParcel(parcel) ?: + parcel->write(touchableRegion) ?: + parcel->writeBool(replaceTouchableRegionWithCrop) ?: + parcel->writeStrongBinder(touchableRegionCropHandle.promote()); + // clang-format on + return status; +} + +status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + if (parcel->readInt32() == 0) { + return OK; + } + + token = parcel->readStrongBinder(); + dispatchingTimeout = static_cast(parcel->readInt64()); + status_t status = parcel->readInt32(&id) ?: parcel->readUtf8FromUtf16(&name); + if (status != OK) { + return status; + } + + flags = Flags(parcel->readInt32()); + type = static_cast(parcel->readInt32()); + float dsdx, dtdx, tx, dtdy, dsdy, ty; + int32_t touchOcclusionModeInt; + // clang-format off + status = parcel->readInt32(&frameLeft) ?: + parcel->readInt32(&frameTop) ?: + parcel->readInt32(&frameRight) ?: + parcel->readInt32(&frameBottom) ?: + parcel->readInt32(&surfaceInset) ?: + parcel->readFloat(&globalScaleFactor) ?: + parcel->readFloat(&alpha) ?: + parcel->readFloat(&dsdx) ?: + parcel->readFloat(&dtdx) ?: + parcel->readFloat(&tx) ?: + parcel->readFloat(&dtdy) ?: + parcel->readFloat(&dsdy) ?: + parcel->readFloat(&ty) ?: + parcel->readInt32(&displayWidth) ?: + parcel->readInt32(&displayHeight) ?: + parcel->readBool(&visible) ?: + parcel->readBool(&focusable) ?: + parcel->readBool(&hasWallpaper) ?: + parcel->readBool(&paused) ?: + parcel->readBool(&trustedOverlay) ?: + parcel->readInt32(&touchOcclusionModeInt) ?: + parcel->readInt32(&ownerPid) ?: + parcel->readInt32(&ownerUid) ?: + parcel->readUtf8FromUtf16(&packageName); + // clang-format on + + if (status != OK) { + return status; + } + + touchOcclusionMode = static_cast(touchOcclusionModeInt); + + inputFeatures = Flags(parcel->readInt32()); + // clang-format off + status = parcel->readInt32(&displayId) ?: + parcel->readInt32(&portalToDisplayId) ?: + applicationInfo.readFromParcel(parcel) ?: + parcel->read(touchableRegion) ?: + parcel->readBool(&replaceTouchableRegionWithCrop); + // clang-format on + + if (status != OK) { + return status; + } + + touchableRegionCropHandle = parcel->readStrongBinder(); + transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); + + return OK; +} + +// --- WindowInfoHandle --- + +WindowInfoHandle::WindowInfoHandle() {} + +WindowInfoHandle::~WindowInfoHandle() {} + +WindowInfoHandle::WindowInfoHandle(const WindowInfoHandle& other) : mInfo(other.mInfo) {} + +WindowInfoHandle::WindowInfoHandle(const WindowInfo& other) : mInfo(other) {} + +status_t WindowInfoHandle::writeToParcel(android::Parcel* parcel) const { + return mInfo.writeToParcel(parcel); +} + +status_t WindowInfoHandle::readFromParcel(const android::Parcel* parcel) { + return mInfo.readFromParcel(parcel); +} + +void WindowInfoHandle::releaseChannel() { + mInfo.token.clear(); +} + +sp WindowInfoHandle::getToken() const { + return mInfo.token; +} + +void WindowInfoHandle::updateFrom(sp handle) { + mInfo = handle->mInfo; +} +} // namespace android::gui -- cgit v1.2.3-59-g8ed1b From 48f8cb998c61fcad3db9ca7bbebc9e424844e6e2 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 26 Aug 2021 14:05:36 -0700 Subject: Report gui::DisplayInfo to clients with window info changes InputFlinger needs to know specifications about displays such as orientation and projection from SurfaceFlinger to support the MotionEvent#getRaw API, which returns coordinates in logical display space at the moment. Since dispatcher gets window information from SF, we need to send the display information that affects input dispatching at the same time as updating window information to ensure those two pieces of information remain in sync. Instead of sending display information along with each window, we attempt to reduce the amount of information sent through binder by sending DisplayInfo separately to WindowInfos. The newly added DisplayInfo struct should only be used by InputFlinger to support raw coordinates for now, with the goal of removing it altogether in the future. Bug: 179274888 Test: atest libgui_test inputflinger_tests Test: manual, ensure input works Change-Id: I87429ca4ced5f105f49a117c676cba29f8a5c4da --- libs/gui/Android.bp | 8 ++- libs/gui/DisplayInfo.cpp | 70 ++++++++++++++++++++++ libs/gui/WindowInfo.cpp | 17 ++---- libs/gui/WindowInfosListenerReporter.cpp | 5 +- libs/gui/android/gui/DisplayInfo.aidl | 19 ++++++ libs/gui/android/gui/IWindowInfosListener.aidl | 3 +- libs/gui/include/gui/DisplayInfo.h | 46 ++++++++++++++ libs/gui/include/gui/WindowInfo.h | 7 --- libs/gui/include/gui/WindowInfosListener.h | 4 +- libs/gui/include/gui/WindowInfosListenerReporter.h | 4 +- libs/gui/tests/Android.bp | 7 ++- libs/gui/tests/DisplayInfo_test.cpp | 49 +++++++++++++++ libs/gui/tests/WindowInfo_test.cpp | 5 -- .../inputflinger/dispatcher/InputDispatcher.cpp | 52 ++++++++++++---- services/inputflinger/dispatcher/InputDispatcher.h | 7 ++- services/surfaceflinger/DisplayDevice.cpp | 28 +++++++++ services/surfaceflinger/DisplayDevice.h | 4 ++ services/surfaceflinger/Layer.cpp | 33 +--------- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 17 +++++- .../surfaceflinger/WindowInfosListenerInvoker.cpp | 4 +- .../surfaceflinger/WindowInfosListenerInvoker.h | 3 +- .../tests/WindowInfosListener_test.cpp | 4 +- 23 files changed, 311 insertions(+), 87 deletions(-) create mode 100644 libs/gui/DisplayInfo.cpp create mode 100644 libs/gui/android/gui/DisplayInfo.aidl create mode 100644 libs/gui/include/gui/DisplayInfo.h create mode 100644 libs/gui/tests/DisplayInfo_test.cpp (limited to 'libs/gui/WindowInfo.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 326da3a7b5..2d1f5a1694 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -65,11 +65,13 @@ cc_library_static { host_supported: true, srcs: [ ":guiconstants_aidl", + "android/gui/DisplayInfo.aidl", "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", "android/gui/IWindowInfosListener.aidl", "android/gui/IWindowInfosReportedListener.aidl", "android/gui/WindowInfo.aidl", + "DisplayInfo.cpp", "WindowInfo.cpp", ], @@ -90,7 +92,7 @@ cc_library_static { ], aidl: { - export_aidl_headers: true + export_aidl_headers: true, }, include_dirs: [ @@ -135,8 +137,8 @@ cc_library_static { ], aidl: { - export_aidl_headers: true - } + export_aidl_headers: true, + }, } cc_library_shared { diff --git a/libs/gui/DisplayInfo.cpp b/libs/gui/DisplayInfo.cpp new file mode 100644 index 0000000000..52d9540eeb --- /dev/null +++ b/libs/gui/DisplayInfo.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "DisplayInfo" + +#include +#include +#include + +#include + +namespace android::gui { + +// --- DisplayInfo --- + +status_t DisplayInfo::readFromParcel(const android::Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + float dsdx, dtdx, tx, dtdy, dsdy, ty; + SAFE_PARCEL(parcel->readInt32, &displayId); + SAFE_PARCEL(parcel->readInt32, &logicalWidth); + SAFE_PARCEL(parcel->readInt32, &logicalHeight); + SAFE_PARCEL(parcel->readFloat, &dsdx); + SAFE_PARCEL(parcel->readFloat, &dtdx); + SAFE_PARCEL(parcel->readFloat, &tx); + SAFE_PARCEL(parcel->readFloat, &dtdy); + SAFE_PARCEL(parcel->readFloat, &dsdy); + SAFE_PARCEL(parcel->readFloat, &ty); + + transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); + + return OK; +} + +status_t DisplayInfo::writeToParcel(android::Parcel* parcel) const { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + SAFE_PARCEL(parcel->writeInt32, displayId); + SAFE_PARCEL(parcel->writeInt32, logicalWidth); + SAFE_PARCEL(parcel->writeInt32, logicalHeight); + SAFE_PARCEL(parcel->writeFloat, transform.dsdx()); + SAFE_PARCEL(parcel->writeFloat, transform.dtdx()); + SAFE_PARCEL(parcel->writeFloat, transform.tx()); + SAFE_PARCEL(parcel->writeFloat, transform.dtdy()); + SAFE_PARCEL(parcel->writeFloat, transform.dsdy()); + SAFE_PARCEL(parcel->writeFloat, transform.ty()); + + return OK; +} + +} // namespace android::gui diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index b2ef7aabc9..5f3a726336 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -54,12 +54,11 @@ bool WindowInfo::operator==(const WindowInfo& info) const { info.frameLeft == frameLeft && info.frameTop == frameTop && info.frameRight == frameRight && info.frameBottom == frameBottom && info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor && - info.transform == transform && info.displayOrientation == displayOrientation && - info.displayWidth == displayWidth && info.displayHeight == displayHeight && - info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible && - info.trustedOverlay == trustedOverlay && info.focusable == focusable && - info.touchOcclusionMode == touchOcclusionMode && info.hasWallpaper == hasWallpaper && - info.paused == paused && info.ownerPid == ownerPid && info.ownerUid == ownerUid && + info.transform == transform && info.touchableRegion.hasSameRects(touchableRegion) && + info.visible == visible && info.trustedOverlay == trustedOverlay && + info.focusable == focusable && info.touchOcclusionMode == touchOcclusionMode && + info.hasWallpaper == hasWallpaper && info.paused == paused && + info.ownerPid == ownerPid && info.ownerUid == ownerUid && info.packageName == packageName && info.inputFeatures == inputFeatures && info.displayId == displayId && info.portalToDisplayId == portalToDisplayId && info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && @@ -97,9 +96,6 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeFloat(transform.dtdy()) ?: parcel->writeFloat(transform.dsdy()) ?: parcel->writeFloat(transform.ty()) ?: - parcel->writeUint32(displayOrientation) ?: - parcel->writeInt32(displayWidth) ?: - parcel->writeInt32(displayHeight) ?: parcel->writeBool(visible) ?: parcel->writeBool(focusable) ?: parcel->writeBool(hasWallpaper) ?: @@ -155,9 +151,6 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->readFloat(&dtdy) ?: parcel->readFloat(&dsdy) ?: parcel->readFloat(&ty) ?: - parcel->readUint32(&displayOrientation) ?: - parcel->readInt32(&displayWidth) ?: - parcel->readInt32(&displayHeight) ?: parcel->readBool(&visible) ?: parcel->readBool(&focusable) ?: parcel->readBool(&hasWallpaper) ?: diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp index c00a4389ad..c32b9ab398 100644 --- a/libs/gui/WindowInfosListenerReporter.cpp +++ b/libs/gui/WindowInfosListenerReporter.cpp @@ -19,6 +19,7 @@ namespace android { +using gui::DisplayInfo; using gui::IWindowInfosReportedListener; using gui::WindowInfo; using gui::WindowInfosListener; @@ -65,7 +66,7 @@ status_t WindowInfosListenerReporter::removeWindowInfosListener( } binder::Status WindowInfosListenerReporter::onWindowInfosChanged( - const std::vector& windowInfos, + const std::vector& windowInfos, const std::vector& displayInfos, const sp& windowInfosReportedListener) { std::unordered_set, ISurfaceComposer::SpHash> windowInfosListeners; @@ -78,7 +79,7 @@ binder::Status WindowInfosListenerReporter::onWindowInfosChanged( } for (auto listener : windowInfosListeners) { - listener->onWindowInfosChanged(windowInfos); + listener->onWindowInfosChanged(windowInfos, displayInfos); } if (windowInfosReportedListener) { diff --git a/libs/gui/android/gui/DisplayInfo.aidl b/libs/gui/android/gui/DisplayInfo.aidl new file mode 100644 index 0000000000..30c088525d --- /dev/null +++ b/libs/gui/android/gui/DisplayInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2021, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +parcelable DisplayInfo cpp_header "gui/DisplayInfo.h"; diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl index d4553ca82d..a5b2762318 100644 --- a/libs/gui/android/gui/IWindowInfosListener.aidl +++ b/libs/gui/android/gui/IWindowInfosListener.aidl @@ -16,11 +16,12 @@ package android.gui; +import android.gui.DisplayInfo; import android.gui.IWindowInfosReportedListener; import android.gui.WindowInfo; /** @hide */ oneway interface IWindowInfosListener { - void onWindowInfosChanged(in WindowInfo[] windowInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener); + void onWindowInfosChanged(in WindowInfo[] windowInfos, in DisplayInfo[] displayInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener); } diff --git a/libs/gui/include/gui/DisplayInfo.h b/libs/gui/include/gui/DisplayInfo.h new file mode 100644 index 0000000000..74f33a2a87 --- /dev/null +++ b/libs/gui/include/gui/DisplayInfo.h @@ -0,0 +1,46 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +namespace android::gui { + +/* + * Describes information about a display that can have windows in it. + * + * This should only be used by InputFlinger to support raw coordinates in logical display space. + */ +struct DisplayInfo : public Parcelable { + int32_t displayId = ADISPLAY_ID_NONE; + + // Logical display dimensions. + int32_t logicalWidth = 0; + int32_t logicalHeight = 0; + + // The display transform. This takes display coordinates to logical display coordinates. + ui::Transform transform; + + status_t writeToParcel(android::Parcel*) const override; + + status_t readFromParcel(const android::Parcel*) override; +}; + +} // namespace android::gui \ No newline at end of file diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index f090c63228..7b7c923a58 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -168,13 +168,6 @@ struct WindowInfo : public Parcelable { // Transform applied to individual windows. ui::Transform transform; - // Display orientation as ui::Transform::RotationFlags. Used for compatibility raw coordinates. - uint32_t displayOrientation = ui::Transform::ROT_0; - - // Display size in its natural rotation. Used to rotate raw coordinates for compatibility. - int32_t displayWidth = 0; - int32_t displayHeight = 0; - /* * This is filled in by the WM relative to the frame and then translated * to absolute coordinates by SurfaceFlinger once the frame is computed. diff --git a/libs/gui/include/gui/WindowInfosListener.h b/libs/gui/include/gui/WindowInfosListener.h index 8a70b9bb57..a18a498c5e 100644 --- a/libs/gui/include/gui/WindowInfosListener.h +++ b/libs/gui/include/gui/WindowInfosListener.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include @@ -23,6 +24,7 @@ namespace android::gui { class WindowInfosListener : public virtual RefBase { public: - virtual void onWindowInfosChanged(const std::vector& /*windowInfos*/) = 0; + virtual void onWindowInfosChanged(const std::vector&, + const std::vector&) = 0; }; } // namespace android::gui \ No newline at end of file diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h index 7cb96e0a30..157a804264 100644 --- a/libs/gui/include/gui/WindowInfosListenerReporter.h +++ b/libs/gui/include/gui/WindowInfosListenerReporter.h @@ -21,7 +21,6 @@ #include #include #include -#include #include namespace android { @@ -30,7 +29,8 @@ class ISurfaceComposer; class WindowInfosListenerReporter : public gui::BnWindowInfosListener { public: static sp getInstance(); - binder::Status onWindowInfosChanged(const std::vector& windowInfos, + binder::Status onWindowInfosChanged(const std::vector&, + const std::vector&, const sp&) override; status_t addWindowInfosListener(const sp& windowInfosListener, diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 3d26c3d858..6dd1073879 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -27,6 +27,7 @@ cc_test { "BufferQueue_test.cpp", "CpuConsumer_test.cpp", "EndToEndNativeInputTest.cpp", + "DisplayInfo_test.cpp", "DisplayedContentSampling_test.cpp", "FillBuffer.cpp", "GLTest.cpp", @@ -62,7 +63,7 @@ cc_test { "libinput", "libui", "libutils", - "libnativewindow" + "libnativewindow", ], header_libs: ["libsurfaceflinger_headers"], @@ -117,7 +118,7 @@ cc_test { "libgui", "libui", "libutils", - "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui. + "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui. "libpdx_default_transport", ], @@ -146,5 +147,5 @@ cc_test { "liblog", "libui", "libutils", - ] + ], } diff --git a/libs/gui/tests/DisplayInfo_test.cpp b/libs/gui/tests/DisplayInfo_test.cpp new file mode 100644 index 0000000000..df3329cd52 --- /dev/null +++ b/libs/gui/tests/DisplayInfo_test.cpp @@ -0,0 +1,49 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include + +namespace android { + +using gui::DisplayInfo; + +namespace test { + +TEST(DisplayInfo, Parcelling) { + DisplayInfo info; + info.displayId = 42; + info.logicalWidth = 99; + info.logicalHeight = 78; + info.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1}); + + Parcel p; + info.writeToParcel(&p); + p.setDataPosition(0); + + DisplayInfo info2; + info2.readFromParcel(&p); + ASSERT_EQ(info.displayId, info2.displayId); + ASSERT_EQ(info.logicalWidth, info2.logicalWidth); + ASSERT_EQ(info.logicalHeight, info2.logicalHeight); + ASSERT_EQ(info.transform, info2.transform); +} + +} // namespace test +} // namespace android diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index a4f436cdba..dcdf76fe35 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -60,9 +60,6 @@ TEST(WindowInfo, Parcelling) { i.globalScaleFactor = 0.3; i.alpha = 0.7; i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1}); - i.displayOrientation = ui::Transform::ROT_0; - i.displayWidth = 1000; - i.displayHeight = 2000; i.visible = false; i.focusable = false; i.hasWallpaper = false; @@ -100,8 +97,6 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor); ASSERT_EQ(i.alpha, i2.alpha); ASSERT_EQ(i.transform, i2.transform); - ASSERT_EQ(i.displayWidth, i2.displayWidth); - ASSERT_EQ(i.displayHeight, i2.displayHeight); ASSERT_EQ(i.visible, i2.visible); ASSERT_EQ(i.focusable, i2.focusable); ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 59cb419d2b..84f5a185d1 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -54,6 +54,7 @@ using android::base::HwTimeoutMultiplier; using android::base::Result; using android::base::StringPrintf; +using android::gui::DisplayInfo; using android::gui::FocusRequest; using android::gui::TouchOcclusionMode; using android::gui::WindowInfo; @@ -2444,9 +2445,15 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowHa inputTarget.inputChannel = inputChannel; inputTarget.flags = targetFlags; inputTarget.globalScaleFactor = windowInfo->globalScaleFactor; - inputTarget.displayOrientation = windowInfo->displayOrientation; - inputTarget.displaySize = - int2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight); + const auto& displayInfoIt = mDisplayInfos.find(windowInfo->displayId); + if (displayInfoIt != mDisplayInfos.end()) { + const auto& displayInfo = displayInfoIt->second; + inputTarget.displayOrientation = displayInfo.transform.getOrientation(); + inputTarget.displaySize = int2(displayInfo.logicalWidth, displayInfo.logicalHeight); + } else { + ALOGI_IF(isPerWindowInputRotationEnabled(), + "DisplayInfo not found for window on display: %d", windowInfo->displayId); + } inputTargets.push_back(inputTarget); it = inputTargets.end() - 1; } @@ -4484,6 +4491,7 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( void InputDispatcher::setInputWindows( const std::unordered_map>>& handlesPerDisplay) { + // TODO(b/198444055): Remove setInputWindows from InputDispatcher. { // acquire lock std::scoped_lock _l(mLock); for (const auto& [displayId, handles] : handlesPerDisplay) { @@ -5013,9 +5021,17 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { } if (!mWindowHandlesByDisplay.empty()) { - for (auto& it : mWindowHandlesByDisplay) { - const std::vector> windowHandles = it.second; - dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first); + for (const auto& [displayId, windowHandles] : mWindowHandlesByDisplay) { + dump += StringPrintf(INDENT "Display: %" PRId32 "\n", displayId); + if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) { + const auto& displayInfo = it->second; + dump += StringPrintf(INDENT2 "logicalSize=%dx%d\n", displayInfo.logicalWidth, + displayInfo.logicalHeight); + displayInfo.transform.dump(dump, "transform", INDENT4); + } else { + dump += INDENT2 "No DisplayInfo found!\n"; + } + if (!windowHandles.empty()) { dump += INDENT2 "Windows:\n"; for (size_t i = 0; i < windowHandles.size(); i++) { @@ -5047,13 +5063,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { windowInfo->inputFeatures.string().c_str()); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64 "ms, trustedOverlay=%s, hasToken=%s, " - "touchOcclusionMode=%s, displayOrientation=%d\n", + "touchOcclusionMode=%s\n", windowInfo->ownerPid, windowInfo->ownerUid, millis(windowInfo->dispatchingTimeout), toString(windowInfo->trustedOverlay), toString(windowInfo->token != nullptr), - toString(windowInfo->touchOcclusionMode).c_str(), - windowInfo->displayOrientation); + toString(windowInfo->touchOcclusionMode).c_str()); windowInfo->transform.dump(dump, "transform", INDENT4); } } else { @@ -6099,16 +6114,29 @@ void InputDispatcher::displayRemoved(int32_t displayId) { mLooper->wake(); } -void InputDispatcher::onWindowInfosChanged(const std::vector& windowInfos) { +void InputDispatcher::onWindowInfosChanged(const std::vector& windowInfos, + const std::vector& displayInfos) { // The listener sends the windows as a flattened array. Separate the windows by display for // more convenient parsing. std::unordered_map>> handlesPerDisplay; - for (const auto& info : windowInfos) { handlesPerDisplay.emplace(info.displayId, std::vector>()); handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info)); } - setInputWindows(handlesPerDisplay); + + { // acquire lock + std::scoped_lock _l(mLock); + mDisplayInfos.clear(); + for (const auto& displayInfo : displayInfos) { + mDisplayInfos.emplace(displayInfo.displayId, displayInfo); + } + + for (const auto& [displayId, handles] : handlesPerDisplay) { + setInputWindowsLocked(handles, displayId); + } + } + // Wake up poll loop since it may need to make new input dispatching choices. + mLooper->wake(); } } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 6df333a154..afe4366c32 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -143,7 +143,8 @@ public: void displayRemoved(int32_t displayId) override; - void onWindowInfosChanged(const std::vector& windowInfos) override; + void onWindowInfosChanged(const std::vector&, + const std::vector&) override; private: enum class DropReason { @@ -337,8 +338,10 @@ private: float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock); android::os::BlockUntrustedTouchesMode mBlockUntrustedTouchesMode GUARDED_BY(mLock); - std::unordered_map>> + std::unordered_map>> mWindowHandlesByDisplay GUARDED_BY(mLock); + std::unordered_map mDisplayInfos + GUARDED_BY(mLock); void setInputWindowsLocked( const std::vector>& inputWindowHandles, int32_t displayId) REQUIRES(mLock); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 802a17d981..fd93b2d8f7 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -139,6 +139,34 @@ uint32_t DisplayDevice::getPageFlipCount() const { return mCompositionDisplay->getRenderSurface()->getPageFlipCount(); } +std::pair DisplayDevice::getInputInfo() const { + gui::DisplayInfo info; + info.displayId = getLayerStack().id; + + // The physical orientation is set when the orientation of the display panel is + // different than the default orientation of the device. Other services like + // InputFlinger do not know about this, so we do not need to expose the physical + // orientation of the panel outside of SurfaceFlinger. + const ui::Rotation inversePhysicalOrientation = ui::ROTATION_0 - mPhysicalOrientation; + auto width = getWidth(); + auto height = getHeight(); + if (inversePhysicalOrientation == ui::ROTATION_90 || + inversePhysicalOrientation == ui::ROTATION_270) { + std::swap(width, height); + } + const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags( + inversePhysicalOrientation), + width, height); + const auto& displayTransform = undoPhysicalOrientation * getTransform(); + // Send the inverse display transform to input so it can convert display coordinates to + // logical display. + info.transform = displayTransform.inverse(); + + info.logicalWidth = getLayerStackSpaceRect().width(); + info.logicalHeight = getLayerStackSpaceRect().height(); + return {info, displayTransform}; +} + // ---------------------------------------------------------------------------- void DisplayDevice::setPowerMode(hal::PowerMode mode) { mPowerMode = mode; diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 43a6bd540a..7762054b4a 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -167,6 +167,10 @@ public: return mDeviceProductInfo; } + // Get the DisplayInfo that will be sent to InputFlinger, and the display transform that should + // be applied to all the input windows on the display. + std::pair getInputInfo() const; + /* ------------------------------------------------------------------------ * Display power mode management. */ diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 804cf9a3a0..2376b83c57 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2131,7 +2131,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet if (traceFlags & SurfaceTracing::TRACE_INPUT) { WindowInfo info; if (useDrawing) { - info = fillInputInfo(nullptr); + info = fillInputInfo(ui::Transform()); } else { info = state.inputInfo; } @@ -2265,7 +2265,7 @@ void Layer::fillTouchOcclusionMode(WindowInfo& info) { } } -WindowInfo Layer::fillInputInfo(const DisplayDevice* display) { +WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) { if (!hasInputInfo()) { mDrawingState.inputInfo.name = getName(); mDrawingState.inputInfo.ownerUid = mOwnerUid; @@ -2279,35 +2279,6 @@ WindowInfo Layer::fillInputInfo(const DisplayDevice* display) { info.id = sequence; info.displayId = getLayerStack().id; - // Transform that maps from LayerStack space to display space, e.g. rotated to non-rotated. - // Used when InputFlinger operates in display space. - ui::Transform displayTransform; - if (display) { - // The physical orientation is set when the orientation of the display panel is different - // than the default orientation of the device. Other services like InputFlinger do not know - // about this, so we do not need to expose the physical orientation of the panel outside of - // SurfaceFlinger. - const ui::Rotation inversePhysicalOrientation = - ui::ROTATION_0 - display->getPhysicalOrientation(); - auto width = display->getWidth(); - auto height = display->getHeight(); - if (inversePhysicalOrientation == ui::ROTATION_90 || - inversePhysicalOrientation == ui::ROTATION_270) { - std::swap(width, height); - } - const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags( - inversePhysicalOrientation), - width, height); - displayTransform = undoPhysicalOrientation * display->getTransform(); - - // Send the inverse of the display orientation so that input can transform points back to - // the rotated display space. - const ui::Rotation inverseOrientation = ui::ROTATION_0 - display->getOrientation(); - info.displayOrientation = ui::Transform::toRotationFlags(inverseOrientation); - - info.displayWidth = width; - info.displayHeight = height; - } fillInputFrameInfo(info, displayTransform); // For compatibility reasons we let layers which can receive input diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4200be4898..3c3c7d0b88 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -851,7 +851,7 @@ public: bool getPremultipledAlpha() const; void setInputInfo(const gui::WindowInfo& info); - gui::WindowInfo fillInputInfo(const DisplayDevice*); + gui::WindowInfo fillInputInfo(const ui::Transform& displayTransform); /** * Returns whether this layer has an explicitly set input-info. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 21b889e264..12389d1663 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -169,6 +169,7 @@ using namespace android::sysprop; using android::hardware::power::Boost; using base::StringAppendF; +using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; using ui::ColorMode; @@ -3053,6 +3054,16 @@ bool enablePerWindowInputRotation() { void SurfaceFlinger::notifyWindowInfos() { std::vector windowInfos; + std::vector displayInfos; + std::unordered_map displayTransforms; + + if (enablePerWindowInputRotation()) { + for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { + const auto& [info, transform] = display->getInputInfo(); + displayInfos.emplace_back(info); + displayTransforms.emplace(display.get(), transform); + } + } mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; @@ -3064,9 +3075,11 @@ void SurfaceFlinger::notifyWindowInfos() { // When calculating the screen bounds we ignore the transparent region since it may // result in an unwanted offset. - windowInfos.push_back(layer->fillInputInfo(display)); + const auto it = displayTransforms.find(display); + windowInfos.push_back( + layer->fillInputInfo(it != displayTransforms.end() ? it->second : ui::Transform())); }); - mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, + mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, mInputWindowCommands.syncInputWindows); } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index dc2aa58c9a..b93d127ab8 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -21,6 +21,7 @@ namespace android { +using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; @@ -67,6 +68,7 @@ void WindowInfosListenerInvoker::binderDied(const wp& who) { } void WindowInfosListenerInvoker::windowInfosChanged(const std::vector& windowInfos, + const std::vector& displayInfos, bool shouldSync) { std::unordered_set, ISurfaceComposer::SpHash> windowInfosListeners; @@ -81,7 +83,7 @@ void WindowInfosListenerInvoker::windowInfosChanged(const std::vectoronWindowInfosChanged(windowInfos, + listener->onWindowInfosChanged(windowInfos, displayInfos, shouldSync ? mWindowInfosReportedListener : nullptr); } } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index 5e5796fe2d..ecd797a631 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -33,7 +33,8 @@ public: void addWindowInfosListener(const sp& windowInfosListener); void removeWindowInfosListener(const sp& windowInfosListener); - void windowInfosChanged(const std::vector& windowInfos, bool shouldSync); + void windowInfosChanged(const std::vector&, + const std::vector&, bool shouldSync); protected: void binderDied(const wp& who) override; diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp index de116f29ca..0069111e09 100644 --- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp +++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp @@ -22,6 +22,7 @@ namespace android { using Transaction = SurfaceComposerClient::Transaction; +using gui::DisplayInfo; using gui::WindowInfo; class WindowInfosListenerTest : public ::testing::Test { @@ -40,7 +41,8 @@ protected: struct SyncWindowInfosListener : public gui::WindowInfosListener { public: - void onWindowInfosChanged(const std::vector& windowInfos) override { + void onWindowInfosChanged(const std::vector& windowInfos, + const std::vector&) override { windowInfosPromise.set_value(windowInfos); } -- cgit v1.2.3-59-g8ed1b From 07e05b60e8331ece4d85106585a42a7533c2976e Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 19 Nov 2021 03:57:24 -0800 Subject: InputDispatcher: Implement spy windows We implement spy windows as outlined in go/spy-windows. Bug: 162194035 Test: atest inputflinger_tests Change-Id: Iea3404329184ab40492666f2a66396e9d8cb3594 --- libs/gui/WindowInfo.cpp | 4 + libs/gui/include/gui/WindowInfo.h | 3 + .../inputflinger/dispatcher/InputDispatcher.cpp | 132 ++++++--- services/inputflinger/dispatcher/InputDispatcher.h | 5 + services/inputflinger/dispatcher/TouchState.cpp | 17 +- services/inputflinger/dispatcher/TouchState.h | 3 +- .../inputflinger/tests/InputDispatcher_test.cpp | 322 ++++++++++++++++++++- 7 files changed, 442 insertions(+), 44 deletions(-) (limited to 'libs/gui/WindowInfo.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 5f3a726336..e92be01e15 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -43,6 +43,10 @@ bool WindowInfo::supportsSplitTouch() const { return flags.test(Flag::SPLIT_TOUCH); } +bool WindowInfo::isSpy() const { + return inputFeatures.test(Feature::SPY); +} + bool WindowInfo::overlaps(const WindowInfo* other) const { return frameLeft < other->frameRight && frameRight > other->frameLeft && frameTop < other->frameBottom && frameBottom > other->frameTop; diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 54a372c23e..808afe40dd 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -137,6 +137,7 @@ struct WindowInfo : public Parcelable { DISABLE_USER_ACTIVITY = 1u << 2, DROP_INPUT = 1u << 3, DROP_INPUT_IF_OBSCURED = 1u << 4, + SPY = 1u << 5, }; /* These values are filled in by the WM and passed through SurfaceFlinger @@ -215,6 +216,8 @@ struct WindowInfo : public Parcelable { bool supportsSplitTouch() const; + bool isSpy() const; + bool overlaps(const WindowInfo* other) const; bool operator==(const WindowInfo& inputChannel) const; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index f50c9e1043..00a3bb05cb 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -1051,14 +1051,14 @@ sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayI LOG_ALWAYS_FATAL("Must provide a valid touch state if adding outside targets"); } // Traverse windows from front to back to find touched window. - const std::vector>& windowHandles = getWindowHandlesLocked(displayId); + const auto& windowHandles = getWindowHandlesLocked(displayId); for (const sp& windowHandle : windowHandles) { if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) { continue; } const WindowInfo& info = *windowHandle->getInfo(); - if (windowAcceptsTouchAt(info, displayId, x, y)) { + if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y)) { return windowHandle; } @@ -1070,6 +1070,27 @@ sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayI return nullptr; } +std::vector> InputDispatcher::findTouchedSpyWindowsAtLocked(int32_t displayId, + int32_t x, + int32_t y) const { + // Traverse windows from front to back and gather the touched spy windows. + std::vector> spyWindows; + const auto& windowHandles = getWindowHandlesLocked(displayId); + for (const sp& windowHandle : windowHandles) { + const WindowInfo& info = *windowHandle->getInfo(); + + if (!windowAcceptsTouchAt(info, displayId, x, y)) { + continue; + } + if (!info.isSpy()) { + // The first touched non-spy window was found, so return the spy windows touched so far. + return spyWindows; + } + spyWindows.push_back(windowHandle); + } + return spyWindows; +} + void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) { const char* reason; switch (dropReason) { @@ -2078,9 +2099,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( } } - std::vector> newTouchedWindows; + std::vector> newTouchedWindows = + findTouchedSpyWindowsAtLocked(displayId, x, y); if (newTouchedWindowHandle != nullptr) { - newTouchedWindows.push_back(newTouchedWindowHandle); + // Process the foreground window first so that it is the first to receive the event. + newTouchedWindows.insert(newTouchedWindows.begin(), newTouchedWindowHandle); } for (const sp& windowHandle : newTouchedWindows) { @@ -2128,8 +2151,10 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // Set target flags. int32_t targetFlags = InputTarget::FLAG_DISPATCH_AS_IS; - // There should only be one new foreground (non-spy) window at this location. - targetFlags |= InputTarget::FLAG_FOREGROUND; + if (!info.isSpy()) { + // There should only be one new foreground (non-spy) window at this location. + targetFlags |= InputTarget::FLAG_FOREGROUND; + } if (isSplit) { targetFlags |= InputTarget::FLAG_SPLIT; @@ -2268,10 +2293,17 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // Check permission to inject into all touched foreground windows and ensure there // is at least one touched foreground window. { - bool haveForegroundWindow = false; + bool haveForegroundOrSpyWindow = false; for (const TouchedWindow& touchedWindow : tempTouchState.windows) { - if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { - haveForegroundWindow = true; + const bool isForeground = + (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0; + if (touchedWindow.windowHandle->getInfo()->isSpy()) { + haveForegroundOrSpyWindow = true; + LOG_ALWAYS_FATAL_IF(isForeground, + "Spy window cannot be dispatched as a foreground window."); + } + if (isForeground) { + haveForegroundOrSpyWindow = true; if (!checkInjectionPermission(touchedWindow.windowHandle, entry.injectionState)) { injectionResult = InputEventInjectionResult::PERMISSION_DENIED; injectionPermission = INJECTION_PERMISSION_DENIED; @@ -2280,8 +2312,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( } } bool hasGestureMonitor = !tempTouchState.gestureMonitors.empty(); - if (!haveForegroundWindow && !hasGestureMonitor) { - ALOGI("Dropping event because there is no touched foreground window in display " + if (!haveForegroundOrSpyWindow && !hasGestureMonitor) { + ALOGI("Dropping event because there is no touched window in display " "%" PRId32 " or gesture monitor to receive it.", displayId); injectionResult = InputEventInjectionResult::FAILED; @@ -5521,58 +5553,78 @@ void InputDispatcher::removeMonitorChannelLocked( status_t InputDispatcher::pilferPointers(const sp& token) { { // acquire lock std::scoped_lock _l(mLock); - std::optional foundDisplayId = findGestureMonitorDisplayByTokenLocked(token); - if (!foundDisplayId) { - ALOGW("Attempted to pilfer pointers from an un-registered monitor or invalid token"); - return BAD_VALUE; + TouchState* statePtr = nullptr; + std::shared_ptr requestingChannel; + int32_t displayId; + int32_t deviceId; + const std::optional foundGestureMonitorDisplayId = + findGestureMonitorDisplayByTokenLocked(token); + + // TODO: Optimize this function for pilfering from windows when removing gesture monitors. + if (foundGestureMonitorDisplayId) { + // A gesture monitor has requested to pilfer pointers. + displayId = *foundGestureMonitorDisplayId; + auto stateIt = mTouchStatesByDisplay.find(displayId); + if (stateIt == mTouchStatesByDisplay.end()) { + ALOGW("Failed to pilfer pointers: no pointers on display %" PRId32 ".", displayId); + return BAD_VALUE; + } + statePtr = &stateIt->second; + + for (const auto& monitor : statePtr->gestureMonitors) { + if (monitor.inputChannel->getConnectionToken() == token) { + requestingChannel = monitor.inputChannel; + deviceId = statePtr->deviceId; + } + } + } else { + // Check if a window has requested to pilfer pointers. + for (auto& [curDisplayId, state] : mTouchStatesByDisplay) { + const sp& windowHandle = state.getWindow(token); + if (windowHandle != nullptr) { + displayId = curDisplayId; + requestingChannel = getInputChannelLocked(token); + deviceId = state.deviceId; + statePtr = &state; + break; + } + } } - int32_t displayId = foundDisplayId.value(); - std::unordered_map::iterator stateIt = - mTouchStatesByDisplay.find(displayId); - if (stateIt == mTouchStatesByDisplay.end()) { - ALOGW("Failed to pilfer pointers: no pointers on display %" PRId32 ".", displayId); + if (requestingChannel == nullptr) { + ALOGW("Attempted to pilfer pointers from an un-registered channel or invalid token"); return BAD_VALUE; } - - TouchState& state = stateIt->second; - std::shared_ptr requestingChannel; - std::optional foundDeviceId; - for (const auto& monitor : state.gestureMonitors) { - if (monitor.inputChannel->getConnectionToken() == token) { - requestingChannel = monitor.inputChannel; - foundDeviceId = state.deviceId; - } - } - if (!foundDeviceId || !state.down) { - ALOGW("Attempted to pilfer points from a monitor without any on-going pointer streams." + TouchState& state = *statePtr; + if (!state.down) { + ALOGW("Attempted to pilfer points from a channel without any on-going pointer streams." " Ignoring."); return BAD_VALUE; } - int32_t deviceId = foundDeviceId.value(); // Send cancel events to all the input channels we're stealing from. CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "gesture monitor stole pointer stream"); + "input channel stole pointer stream"); options.deviceId = deviceId; options.displayId = displayId; - std::string canceledWindows = "["; + std::string canceledWindows; for (const TouchedWindow& window : state.windows) { std::shared_ptr channel = getInputChannelLocked(window.windowHandle->getToken()); - if (channel != nullptr) { + if (channel != nullptr && channel->getConnectionToken() != token) { synthesizeCancelationEventsForInputChannelLocked(channel, options); - canceledWindows += channel->getName() + ", "; + canceledWindows += canceledWindows.empty() ? "[" : ", "; + canceledWindows += channel->getName(); } } - canceledWindows += "]"; - ALOGI("Monitor %s is stealing touch from %s", requestingChannel->getName().c_str(), + canceledWindows += canceledWindows.empty() ? "[]" : "]"; + ALOGI("Channel %s is stealing touch from %s", requestingChannel->getName().c_str(), canceledWindows.c_str()); // Then clear the current touch state so we stop dispatching to them as well. state.split = false; - state.filterNonMonitors(); + state.filterWindowsExcept(token); } return OK; } diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 8a551cfca1..cd176b5cc9 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -238,6 +238,11 @@ private: bool ignoreDragWindow = false) REQUIRES(mLock); + std::vector> findTouchedSpyWindowsAtLocked(int32_t displayId, + int32_t x, + int32_t y) const + REQUIRES(mLock); + sp getConnectionLocked(const sp& inputConnectionToken) const REQUIRES(mLock); diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index 759b3e7097..d624e99acf 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -105,8 +105,11 @@ void TouchState::filterNonAsIsTouchWindows() { } } -void TouchState::filterNonMonitors() { - windows.clear(); +void TouchState::filterWindowsExcept(const sp& token) { + auto it = std::remove_if(windows.begin(), windows.end(), [&token](const TouchedWindow& w) { + return w.windowHandle->getToken() != token; + }); + windows.erase(it, windows.end()); } sp TouchState::getFirstForegroundWindowHandle() const { @@ -144,4 +147,14 @@ sp TouchState::getWallpaperWindow() const { return nullptr; } +sp TouchState::getWindow(const sp& token) const { + for (const TouchedWindow& touchedWindow : windows) { + const auto& windowHandle = touchedWindow.windowHandle; + if (windowHandle->getToken() == token) { + return windowHandle; + } + } + return nullptr; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 762cc8ab9e..83ca90197b 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -47,10 +47,11 @@ struct TouchState { void addGestureMonitors(const std::vector& monitors); void removeWindowByToken(const sp& token); void filterNonAsIsTouchWindows(); - void filterNonMonitors(); + void filterWindowsExcept(const sp& token); sp getFirstForegroundWindowHandle() const; bool isSlippery() const; sp getWallpaperWindow() const; + sp getWindow(const sp&) const; }; } // namespace inputdispatcher diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 2c64271cca..0dd990e46c 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -953,6 +954,8 @@ public: sp getToken() { return mConsumer->getChannel()->getConnectionToken(); } + int getChannelFd() { return mConsumer->getChannel()->getFd().get(); } + protected: std::unique_ptr mConsumer; PreallocatedInputEventFactory mEventFactory; @@ -1041,6 +1044,8 @@ public: mInfo.transform = translate * displayTransform; } + void setTouchableRegion(const Region& region) { mInfo.touchableRegion = region; } + void setType(WindowInfo::Type type) { mInfo.type = type; } void setHasWallpaper(bool hasWallpaper) { mInfo.hasWallpaper = hasWallpaper; } @@ -1208,6 +1213,8 @@ public: void destroyReceiver() { mInputReceiver = nullptr; } + int getChannelFd() { return mInputReceiver->getChannelFd(); } + private: const std::string mName; std::unique_ptr mInputReceiver; @@ -1387,7 +1394,7 @@ static InputEventInjectionResult injectMotionEvent( static InputEventInjectionResult injectMotionEvent( const std::unique_ptr& dispatcher, int32_t action, int32_t source, - int32_t displayId, const PointF& position, + int32_t displayId, const PointF& position = {100, 200}, const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION}, std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT, @@ -6237,4 +6244,317 @@ TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTou mSecondWindow->assertNoEvents(); } +class InputDispatcherSpyWindowTest : public InputDispatcherTest { +public: + sp createSpy(const Flags flags) { + std::shared_ptr application = + std::make_shared(); + std::string name = "Fake Spy "; + name += std::to_string(mSpyCount++); + sp spy = + new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT); + spy->setInputFeatures(WindowInfo::Feature::SPY); + spy->addFlags(flags); + return spy; + } + + sp createForeground() { + std::shared_ptr application = + std::make_shared(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + window->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + return window; + } + +private: + int mSpyCount{0}; +}; + +/** + * Input injection into a display with a spy window but no foreground windows should succeed. + */ +TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) { + auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); +} + +/** + * Verify the order in which different input windows receive events. The touched foreground window + * (if there is one) should always receive the event first. When there are multiple spy windows, the + * spy windows will receive the event according to their Z-order, where the top-most spy window will + * receive events before ones belows it. + * + * Here, we set up a scenario with four windows in the following Z order from the top: + * spy1, spy2, window, spy3. + * We then inject an event and verify that the foreground "window" receives it first, followed by + * "spy1" and "spy2". The "spy3" does not receive the event because it is underneath the foreground + * window. + */ +TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) { + auto window = createForeground(); + auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy3 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window, spy3}}}); + const std::vector> channels{spy1, spy2, window, spy3}; + const size_t numChannels = channels.size(); + + base::unique_fd epollFd(epoll_create1(0 /*flags*/)); + if (!epollFd.ok()) { + FAIL() << "Failed to create epoll fd"; + } + + for (size_t i = 0; i < numChannels; i++) { + struct epoll_event event = {.events = EPOLLIN, .data.u64 = i}; + if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, channels[i]->getChannelFd(), &event) < 0) { + FAIL() << "Failed to add fd to epoll"; + } + } + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + std::vector eventOrder; + std::vector events(numChannels); + for (;;) { + const int nFds = epoll_wait(epollFd.get(), events.data(), static_cast(numChannels), + (100ms).count()); + if (nFds < 0) { + FAIL() << "Failed to call epoll_wait"; + } + if (nFds == 0) { + break; // epoll_wait timed out + } + for (int i = 0; i < nFds; i++) { + ASSERT_EQ(EPOLLIN, events[i].events); + eventOrder.push_back(events[i].data.u64); + channels[i]->consumeMotionDown(); + } + } + + // Verify the order in which the events were received. + EXPECT_EQ(3u, eventOrder.size()); + EXPECT_EQ(2u, eventOrder[0]); // index 2: window + EXPECT_EQ(0u, eventOrder[1]); // index 0: spy1 + EXPECT_EQ(1u, eventOrder[2]); // index 1: spy2 +} + +/** + * A spy window using the NOT_TOUCHABLE flag does not receive events. + */ +TEST_F(InputDispatcherSpyWindowTest, NotTouchable) { + auto window = createForeground(); + auto spy = createSpy(WindowInfo::Flag::NOT_TOUCHABLE); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + spy->assertNoEvents(); +} + +/** + * A spy window will only receive gestures that originate within its touchable region. Gestures that + * have their ACTION_DOWN outside of the touchable region of the spy window will not be dispatched + * to the window. + */ +TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) { + auto window = createForeground(); + auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + spy->setTouchableRegion(Region{{0, 0, 20, 20}}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + + // Inject an event outside the spy window's touchable region. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionDown(); + spy->assertNoEvents(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionUp(); + spy->assertNoEvents(); + + // Inject an event inside the spy window's touchable region. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {5, 10})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionDown(); + spy->consumeMotionDown(); +} + +/** + * A spy window that is a modal window will receive gestures outside of its frame and touchable + * region. + */ +TEST_F(InputDispatcherSpyWindowTest, ModalWindow) { + auto window = createForeground(); + auto spy = createSpy(static_cast(0)); + // This spy window does not have the NOT_TOUCH_MODAL flag set. + spy->setFrame(Rect{0, 0, 20, 20}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + + // Inject an event outside the spy window's frame and touchable region. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionDown(); + spy->consumeMotionDown(); +} + +/** + * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES + * flag. + */ +TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { + auto window = createForeground(); + auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::WATCH_OUTSIDE_TOUCH); + spy->setFrame(Rect{0, 0, 20, 20}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + + // Inject an event outside the spy window's frame and touchable region. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionDown(); + spy->consumeMotionOutside(); +} + +/** + * When configured to block untrusted touches, events will not be dispatched to windows below a spy + * window if it is not a trusted overly. + */ +TEST_F(InputDispatcherSpyWindowTest, BlockUntrustedTouches) { + mDispatcher->setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode::BLOCK); + + auto window = createForeground(); + auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + window->setOwnerInfo(111, 111); + spy->setOwnerInfo(222, 222); + spy->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + + // Inject an event outside the spy window's frame and touchable region. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + spy->consumeMotionDown(); + window->assertNoEvents(); +} + +/** + * A spy window can pilfer pointers. When this happens, touch gestures that are currently sent to + * any other windows - including other spy windows - will also be cancelled. + */ +TEST_F(InputDispatcherSpyWindowTest, PilferPointers) { + auto window = createForeground(); + auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window}}}); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionDown(); + spy1->consumeMotionDown(); + spy2->consumeMotionDown(); + + // Pilfer pointers from the second spy window. + mDispatcher->pilferPointers(spy2->getToken()); + spy2->assertNoEvents(); + spy1->consumeMotionCancel(); + window->consumeMotionCancel(); + + // The rest of the gesture should only be sent to the second spy window. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + spy2->consumeMotionMove(); + spy1->assertNoEvents(); + window->assertNoEvents(); +} + +/** + * Even when a spy window spans over multiple foreground windows, the spy should receive all + * pointers that are down within its bounds. + */ +TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { + auto windowLeft = createForeground(); + windowLeft->setFrame({0, 0, 100, 200}); + auto windowRight = createForeground(); + windowRight->setFrame({100, 0, 200, 200}); + auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + spy->setFrame({0, 0, 200, 200}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, windowLeft, windowRight}}}); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + windowLeft->consumeMotionDown(); + spy->consumeMotionDown(); + + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer( + PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + windowRight->consumeMotionDown(); + spy->consumeMotionPointerDown(1 /*pointerIndex*/); +} + +/** + * When the first pointer lands outside the spy window and the second pointer lands inside it, the + * the spy should receive the second pointer with ACTION_DOWN. + */ +TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { + auto window = createForeground(); + window->setFrame({0, 0, 200, 200}); + auto spyRight = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + spyRight->setFrame({100, 0, 200, 200}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyRight, window}}}); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionDown(); + spyRight->assertNoEvents(); + + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer( + PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionPointerDown(1 /*pointerIndex*/); + spyRight->consumeMotionDown(); +} + } // namespace android::inputdispatcher -- cgit v1.2.3-59-g8ed1b From d65552bbf071479c08b3eb7295a2844194241bca Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 7 Oct 2021 11:23:50 -0700 Subject: InputDispatcher: Implement stylus interceptor A stylus interceptor is a window that receives all stylus events within its touchable bounds, while letting all other events be dispatched to windows behind it. This makes it possible for the framework to create a stylus interceptor on top of another app to implement handwriting recognition. The feature has no effect when the window flag FLAG_NOT_TOUCHABLE is not set. The feature has no effect when the window is not a trusted overlay. Test: atest inputflinger_tests Change-Id: Id4833840aa3088d21333d3ea08beffbded4debbc --- libs/gui/WindowInfo.cpp | 4 + libs/gui/include/gui/WindowInfo.h | 3 + .../inputflinger/dispatcher/InputDispatcher.cpp | 60 +++++++++---- services/inputflinger/dispatcher/InputDispatcher.h | 14 ++-- .../inputflinger/tests/InputDispatcher_test.cpp | 98 +++++++++++++++++++++- 5 files changed, 153 insertions(+), 26 deletions(-) (limited to 'libs/gui/WindowInfo.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index e92be01e15..8d356aaaa1 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -47,6 +47,10 @@ bool WindowInfo::isSpy() const { return inputFeatures.test(Feature::SPY); } +bool WindowInfo::interceptsStylus() const { + return inputFeatures.test(Feature::INTERCEPTS_STYLUS); +} + bool WindowInfo::overlaps(const WindowInfo* other) const { return frameLeft < other->frameRight && frameRight > other->frameLeft && frameTop < other->frameBottom && frameBottom > other->frameTop; diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 808afe40dd..027371744d 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -138,6 +138,7 @@ struct WindowInfo : public Parcelable { DROP_INPUT = 1u << 3, DROP_INPUT_IF_OBSCURED = 1u << 4, SPY = 1u << 5, + INTERCEPTS_STYLUS = 1u << 6, }; /* These values are filled in by the WM and passed through SurfaceFlinger @@ -218,6 +219,8 @@ struct WindowInfo : public Parcelable { bool isSpy() const; + bool interceptsStylus() const; + bool overlaps(const WindowInfo* other) const; bool operator==(const WindowInfo& inputChannel) const; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 6ff245081a..98a73d412c 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -530,12 +530,14 @@ bool isUserActivityEvent(const EventEntry& eventEntry) { } // Returns true if the given window can accept pointer events at the given display location. -bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y) { +bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y, + bool isStylus) { if (windowInfo.displayId != displayId || !windowInfo.visible) { return false; } const auto flags = windowInfo.flags; - if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) { + const bool windowCanInterceptTouch = isStylus && windowInfo.interceptsStylus(); + if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE) && !windowCanInterceptTouch) { return false; } const bool isModalWindow = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) && @@ -546,6 +548,12 @@ bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32 return true; } +bool isPointerFromStylus(const MotionEntry& entry, int32_t pointerIndex) { + return isFromSource(entry.source, AINPUT_SOURCE_STYLUS) && + (entry.pointerProperties[pointerIndex].toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS || + entry.pointerProperties[pointerIndex].toolType == AMOTION_EVENT_TOOL_TYPE_ERASER); +} + } // namespace // --- InputDispatcher --- @@ -939,8 +947,10 @@ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEnt motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = static_cast( motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); + + const bool isStylus = isPointerFromStylus(motionEntry, 0 /*pointerIndex*/); sp touchedWindowHandle = - findTouchedWindowAtLocked(displayId, x, y, nullptr); + findTouchedWindowAtLocked(displayId, x, y, nullptr, isStylus); if (touchedWindowHandle != nullptr && touchedWindowHandle->getApplicationToken() != mAwaitedFocusedApplication->getApplicationToken()) { @@ -1045,6 +1055,7 @@ void InputDispatcher::addRecentEventLocked(std::shared_ptr entry) { sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, TouchState* touchState, + bool isStylus, bool addOutsideTargets, bool ignoreDragWindow) { if (addOutsideTargets && touchState == nullptr) { @@ -1058,7 +1069,7 @@ sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayI } const WindowInfo& info = *windowHandle->getInfo(); - if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y)) { + if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y, isStylus)) { return windowHandle; } @@ -1070,16 +1081,15 @@ sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayI return nullptr; } -std::vector> InputDispatcher::findTouchedSpyWindowsAtLocked(int32_t displayId, - int32_t x, - int32_t y) const { +std::vector> InputDispatcher::findTouchedSpyWindowsAtLocked( + int32_t displayId, int32_t x, int32_t y, bool isStylus) const { // Traverse windows from front to back and gather the touched spy windows. std::vector> spyWindows; const auto& windowHandles = getWindowHandlesLocked(displayId); for (const sp& windowHandle : windowHandles) { const WindowInfo& info = *windowHandle->getInfo(); - if (!windowAcceptsTouchAt(info, displayId, x, y)) { + if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus)) { continue; } if (!info.isSpy()) { @@ -2062,8 +2072,9 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)); } const bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN; + const bool isStylus = isPointerFromStylus(entry, pointerIndex); newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, - isDown /*addOutsideTargets*/); + isStylus, isDown /*addOutsideTargets*/); // Handle the case where we did not find a window. if (newTouchedWindowHandle == nullptr) { @@ -2100,7 +2111,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( } std::vector> newTouchedWindows = - findTouchedSpyWindowsAtLocked(displayId, x, y); + findTouchedSpyWindowsAtLocked(displayId, x, y, isStylus); if (newTouchedWindowHandle != nullptr) { // Process the foreground window first so that it is the first to receive the event. newTouchedWindows.insert(newTouchedWindows.begin(), newTouchedWindowHandle); @@ -2213,9 +2224,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( const int32_t x = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); const int32_t y = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); + const bool isStylus = isPointerFromStylus(entry, 0 /*pointerIndex*/); sp oldTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); - newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState); + newTouchedWindowHandle = + findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, isStylus); // Drop touch events if requested by input feature if (newTouchedWindowHandle != nullptr && @@ -2477,8 +2490,12 @@ Failed: } void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) { + // Prevent stylus interceptor windows from affecting drag and drop behavior for now, until we + // have an explicit reason to support it. + constexpr bool isStylus = false; + const sp dropWindow = - findTouchedWindowAtLocked(displayId, x, y, nullptr /*touchState*/, + findTouchedWindowAtLocked(displayId, x, y, nullptr /*touchState*/, isStylus, false /*addOutsideTargets*/, true /*ignoreDragWindow*/); if (dropWindow) { vec2 local = dropWindow->getInfo()->transform.transform(x, y); @@ -2511,8 +2528,12 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { return; } + // Prevent stylus interceptor windows from affecting drag and drop behavior for now, until + // we have an explicit reason to support it. + constexpr bool isStylus = false; + const sp hoverWindowHandle = - findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/, + findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/, isStylus, false /*addOutsideTargets*/, true /*ignoreDragWindow*/); // enqueue drag exit if needed. if (hoverWindowHandle != mDragState->dragHoverWindowHandle && @@ -4685,15 +4706,22 @@ void InputDispatcher::setInputWindowsLocked( ALOGD("setInputWindows displayId=%" PRId32 " %s", displayId, windowList.c_str()); } - // Ensure all tokens are null if the window has feature NO_INPUT_CHANNEL + // Check preconditions for new input windows for (const sp& window : windowInfoHandles) { - const bool noInputWindow = - window->getInfo()->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); + const WindowInfo& info = *window->getInfo(); + + // Ensure all tokens are null if the window has feature NO_INPUT_CHANNEL + const bool noInputWindow = info.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); if (noInputWindow && window->getToken() != nullptr) { ALOGE("%s has feature NO_INPUT_WINDOW, but a non-null token. Clearing", window->getName().c_str()); window->releaseChannel(); } + + // Ensure all stylus interceptors are trusted overlays + LOG_ALWAYS_FATAL_IF(info.interceptsStylus() && !info.trustedOverlay, + "%s has feature INTERCEPTS_STYLUS, but is not a trusted overlay.", + window->getName().c_str()); } // Copy old handles for release if they are no longer present. diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index fb9c81b4f6..f8ab7ee4fe 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -234,16 +234,12 @@ private: // to transfer focus to a new application. std::shared_ptr mNextUnblockedEvent GUARDED_BY(mLock); - sp findTouchedWindowAtLocked(int32_t displayId, int32_t x, - int32_t y, TouchState* touchState, - bool addOutsideTargets = false, - bool ignoreDragWindow = false) - REQUIRES(mLock); + sp findTouchedWindowAtLocked( + int32_t displayId, int32_t x, int32_t y, TouchState* touchState, bool isStylus = false, + bool addOutsideTargets = false, bool ignoreDragWindow = false) REQUIRES(mLock); - std::vector> findTouchedSpyWindowsAtLocked(int32_t displayId, - int32_t x, - int32_t y) const - REQUIRES(mLock); + std::vector> findTouchedSpyWindowsAtLocked( + int32_t displayId, int32_t x, int32_t y, bool isStylus) const REQUIRES(mLock); sp getConnectionLocked(const sp& inputConnectionToken) const REQUIRES(mLock); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index ba70929792..b2d0fb841c 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1003,6 +1003,7 @@ public: mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = displayId; + mInfo.trustedOverlay = false; } sp clone( @@ -1054,7 +1055,9 @@ public: void setFlags(Flags flags) { mInfo.flags = flags; } - void setInputFeatures(WindowInfo::Feature features) { mInfo.inputFeatures = features; } + void setInputFeatures(Flags features) { mInfo.inputFeatures = features; } + + void setTrustedOverlay(bool trustedOverlay) { mInfo.trustedOverlay = trustedOverlay; } void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) { mInfo.transform.set(dsdx, dtdx, dtdy, dsdy); @@ -6600,4 +6603,97 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { spyRight->consumeMotionDown(); } +class InputDispatcherStylusInterceptorTest : public InputDispatcherTest { +public: + std::pair, sp> setupStylusOverlayScenario() { + std::shared_ptr overlayApplication = + std::make_shared(); + sp overlay = + new FakeWindowHandle(overlayApplication, mDispatcher, "Stylus interceptor window", + ADISPLAY_ID_DEFAULT); + overlay->setFocusable(false); + overlay->setOwnerInfo(111, 111); + overlay->setFlags(WindowInfo::Flag::NOT_TOUCHABLE | WindowInfo::Flag::SPLIT_TOUCH); + overlay->setInputFeatures(WindowInfo::Feature::INTERCEPTS_STYLUS); + overlay->setTrustedOverlay(true); + + std::shared_ptr application = + std::make_shared(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Application window", + ADISPLAY_ID_DEFAULT); + window->setFocusable(true); + window->setOwnerInfo(222, 222); + window->setFlags(WindowInfo::Flag::SPLIT_TOUCH); + + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); + setFocusedWindow(window); + window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/); + return {std::move(overlay), std::move(window)}; + } + + void sendFingerEvent(int32_t action) { + NotifyMotionArgs motionArgs = + generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, + ADISPLAY_ID_DEFAULT, {PointF{20, 20}}); + mDispatcher->notifyMotion(&motionArgs); + } + + void sendStylusEvent(int32_t action) { + NotifyMotionArgs motionArgs = + generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, + ADISPLAY_ID_DEFAULT, {PointF{30, 40}}); + motionArgs.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + mDispatcher->notifyMotion(&motionArgs); + } +}; + +TEST_F(InputDispatcherStylusInterceptorTest, UntrustedOverlay_AbortsDispatcher) { + auto [overlay, window] = setupStylusOverlayScenario(); + overlay->setTrustedOverlay(false); + // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort. + ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}), + ".* not a trusted overlay"); +} + +TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) { + auto [overlay, window] = setupStylusOverlayScenario(); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); + + sendStylusEvent(AMOTION_EVENT_ACTION_DOWN); + overlay->consumeMotionDown(); + sendStylusEvent(AMOTION_EVENT_ACTION_UP); + overlay->consumeMotionUp(); + + sendFingerEvent(AMOTION_EVENT_ACTION_DOWN); + window->consumeMotionDown(); + sendFingerEvent(AMOTION_EVENT_ACTION_UP); + window->consumeMotionUp(); + + overlay->assertNoEvents(); + window->assertNoEvents(); +} + +TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) { + auto [overlay, window] = setupStylusOverlayScenario(); + overlay->setInputFeatures(overlay->getInfo()->inputFeatures | WindowInfo::Feature::SPY); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); + + sendStylusEvent(AMOTION_EVENT_ACTION_DOWN); + overlay->consumeMotionDown(); + window->consumeMotionDown(); + sendStylusEvent(AMOTION_EVENT_ACTION_UP); + overlay->consumeMotionUp(); + window->consumeMotionUp(); + + sendFingerEvent(AMOTION_EVENT_ACTION_DOWN); + window->consumeMotionDown(); + sendFingerEvent(AMOTION_EVENT_ACTION_UP); + window->consumeMotionUp(); + + overlay->assertNoEvents(); + window->assertNoEvents(); +} + } // namespace android::inputdispatcher -- cgit v1.2.3-59-g8ed1b From 6fa425a82c0ff753d7bd1b98eef1d70154c54f88 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 16 Dec 2021 07:16:04 -0800 Subject: SF: Calculate WindowInfo frame correctly for all layers The old logic skipped transform calculation using an early return if the layer bounds were invalid. This skipped the calculations which transformed the WindowInfo frame into display space. This also resulted in container layers being misconfigured, since they did not have their input bounds calculated correctly. Allow all layers to have their WindowInfo calculated correctly in display space, even if their input bounds happen to be invalid. Bug: 162194035 Test: atest libgui_test Test: manual Change-Id: I7b3c361bb9a12adf52586d3a940501e4d8a9e667 --- libs/gui/WindowInfo.cpp | 3 +- libs/gui/tests/EndToEndNativeInputTest.cpp | 76 ++++++++++++++++++++++++++++++ services/surfaceflinger/Layer.cpp | 24 +++------- services/surfaceflinger/Layer.h | 13 +++++ 4 files changed, 98 insertions(+), 18 deletions(-) (limited to 'libs/gui/WindowInfo.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 8d356aaaa1..1c7b270527 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -52,7 +52,8 @@ bool WindowInfo::interceptsStylus() const { } bool WindowInfo::overlaps(const WindowInfo* other) const { - return frameLeft < other->frameRight && frameRight > other->frameLeft && + const bool nonEmpty = (frameRight - frameLeft > 0) || (frameBottom - frameTop > 0); + return nonEmpty && frameLeft < other->frameRight && frameRight > other->frameLeft && frameTop < other->frameBottom && frameBottom > other->frameTop; } diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 6f1263bb89..83e9858875 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -987,6 +987,82 @@ TEST_F(InputSurfacesTest, drop_input_policy) { EXPECT_EQ(surface->consumeEvent(100), nullptr); } +/** + * If a cropped layer's touchable region is replaced with a null crop, it should receive input in + * its own crop. + */ +TEST_F(InputSurfacesTest, cropped_container_replaces_touchable_region_with_null_crop) { + std::unique_ptr parentContainer = + InputSurface::makeContainerInputSurface(mComposerClient, 0, 0); + std::unique_ptr containerSurface = + InputSurface::makeContainerInputSurface(mComposerClient, 100, 100); + containerSurface->doTransaction( + [&](auto &t, auto &sc) { t.reparent(sc, parentContainer->mSurfaceControl); }); + containerSurface->mInputInfo.replaceTouchableRegionWithCrop = true; + containerSurface->mInputInfo.touchableRegionCropHandle = nullptr; + parentContainer->showAt(10, 10, Rect(0, 0, 20, 20)); + containerSurface->showAt(10, 10, Rect(0, 0, 5, 5)); + + // Receives events inside its own crop + injectTap(21, 21); + containerSurface->expectTap(1, 1); // Event is in layer space + + // Does not receive events outside its crop + injectTap(26, 26); + EXPECT_EQ(containerSurface->consumeEvent(100), nullptr); +} + +/** + * If an un-cropped layer's touchable region is replaced with a null crop, it should receive input + * in its parent's touchable region. The input events should be in the layer's coordinate space. + */ +TEST_F(InputSurfacesTest, uncropped_container_replaces_touchable_region_with_null_crop) { + std::unique_ptr parentContainer = + InputSurface::makeContainerInputSurface(mComposerClient, 0, 0); + std::unique_ptr containerSurface = + InputSurface::makeContainerInputSurface(mComposerClient, 100, 100); + containerSurface->doTransaction( + [&](auto &t, auto &sc) { t.reparent(sc, parentContainer->mSurfaceControl); }); + containerSurface->mInputInfo.replaceTouchableRegionWithCrop = true; + containerSurface->mInputInfo.touchableRegionCropHandle = nullptr; + parentContainer->showAt(10, 10, Rect(0, 0, 20, 20)); + containerSurface->showAt(10, 10, Rect::INVALID_RECT); + + // Receives events inside parent bounds + injectTap(21, 21); + containerSurface->expectTap(1, 1); // Event is in layer space + + // Does not receive events outside parent bounds + injectTap(31, 31); + EXPECT_EQ(containerSurface->consumeEvent(100), nullptr); +} + +/** + * If a layer's touchable region is replaced with a layer crop, it should receive input in the crop + * layer's bounds. The input events should be in the layer's coordinate space. + */ +TEST_F(InputSurfacesTest, replace_touchable_region_with_crop) { + std::unique_ptr cropLayer = + InputSurface::makeContainerInputSurface(mComposerClient, 0, 0); + cropLayer->showAt(50, 50, Rect(0, 0, 20, 20)); + + std::unique_ptr containerSurface = + InputSurface::makeContainerInputSurface(mComposerClient, 100, 100); + containerSurface->mInputInfo.replaceTouchableRegionWithCrop = true; + containerSurface->mInputInfo.touchableRegionCropHandle = + cropLayer->mSurfaceControl->getHandle(); + containerSurface->showAt(10, 10, Rect::INVALID_RECT); + + // Receives events inside crop layer bounds + injectTap(51, 51); + containerSurface->expectTap(41, 41); // Event is in layer space + + // Does not receive events outside crop layer bounds + injectTap(21, 21); + injectTap(71, 71); + EXPECT_EQ(containerSurface->consumeEvent(100), nullptr); +} + class MultiDisplayTests : public InputSurfacesTest { public: MultiDisplayTests() : InputSurfacesTest() { ProcessState::self()->startThreadPool(); } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index fa2c92dd32..5175be9b9d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2167,25 +2167,15 @@ Rect Layer::getInputBounds() const { } void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTransform) { - // Transform layer size to screen space and inset it by surface insets. - // If this is a portal window, set the touchableRegion to the layerBounds. - Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE - ? getInputBounds() - : info.touchableRegion.getBounds(); + Rect layerBounds = getInputBounds(); if (!layerBounds.isValid()) { - layerBounds = getInputBounds(); - } - - if (!layerBounds.isValid()) { - // If the layer bounds is empty, set the frame to empty and clear the transform - info.frameLeft = 0; - info.frameTop = 0; - info.frameRight = 0; - info.frameBottom = 0; - info.transform.reset(); - info.touchableRegion = Region(); info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE; - return; + info.touchableRegion.clear(); + // A layer could have invalid input bounds and still expect to receive touch input if it has + // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated + // correctly to determine the coordinate space for input events. Use an empty rect so that + // the layer will receive input in its own layer space. + layerBounds = Rect::EMPTY_RECT; } const ui::Transform layerTransform = getInputTransform(); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4cdd8fa24b..9e10b4f02f 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -959,6 +959,19 @@ protected: bool usingRelativeZ(LayerVector::StateSet) const; virtual ui::Transform getInputTransform() const; + /** + * Get the bounds in layer space within which this layer can receive input. + * + * These bounds are used to: + * - Determine the input frame for the layer to be used for occlusion detection; and + * - Determine the coordinate space within which the layer will receive input. The top-left of + * this rect will be the origin of the coordinate space that the input events sent to the + * layer will be in (prior to accounting for surface insets). + * + * The layer can still receive touch input if these bounds are invalid if + * "replaceTouchableRegionWithCrop" is specified. In this case, the layer will receive input + * in this layer's space, regardless of the specified crop layer. + */ virtual Rect getInputBounds() const; // constant -- cgit v1.2.3-59-g8ed1b From 1c58c0d96d2101c25652692a89796d208afc522b Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Wed, 29 Dec 2021 02:10:29 -0800 Subject: WindowInfo: Remove unused field portalToDisplayId Bug: None Test: presubmit Change-Id: If3d6ea21e47c87838c207cd9c08c6ea09d004b7c --- libs/gui/WindowInfo.cpp | 4 +--- libs/gui/include/gui/WindowInfo.h | 1 - libs/gui/tests/WindowInfo_test.cpp | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) (limited to 'libs/gui/WindowInfo.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 1c7b270527..a8667867b2 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -69,7 +69,7 @@ bool WindowInfo::operator==(const WindowInfo& info) const { info.hasWallpaper == hasWallpaper && info.paused == paused && info.ownerPid == ownerPid && info.ownerUid == ownerUid && info.packageName == packageName && info.inputFeatures == inputFeatures && - info.displayId == displayId && info.portalToDisplayId == portalToDisplayId && + info.displayId == displayId && info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && info.applicationInfo == applicationInfo; } @@ -116,7 +116,6 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeUtf8AsUtf16(packageName) ?: parcel->writeInt32(inputFeatures.get()) ?: parcel->writeInt32(displayId) ?: - parcel->writeInt32(portalToDisplayId) ?: applicationInfo.writeToParcel(parcel) ?: parcel->write(touchableRegion) ?: parcel->writeBool(replaceTouchableRegionWithCrop) ?: @@ -180,7 +179,6 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { inputFeatures = Flags(parcel->readInt32()); // clang-format off status = parcel->readInt32(&displayId) ?: - parcel->readInt32(&portalToDisplayId) ?: applicationInfo.readFromParcel(parcel) ?: parcel->read(touchableRegion) ?: parcel->readBool(&replaceTouchableRegionWithCrop); diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 2bfaec8d03..eb64ac9b25 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -214,7 +214,6 @@ struct WindowInfo : public Parcelable { std::string packageName; Flags inputFeatures; int32_t displayId = ADISPLAY_ID_NONE; - int32_t portalToDisplayId = ADISPLAY_ID_NONE; InputApplicationInfo applicationInfo; bool replaceTouchableRegionWithCrop = false; wp touchableRegionCropHandle; diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index dcdf76fe35..ff3ba2aae0 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -70,7 +70,6 @@ TEST(WindowInfo, Parcelling) { i.packageName = "com.example.package"; i.inputFeatures = WindowInfo::Feature::DISABLE_USER_ACTIVITY; i.displayId = 34; - i.portalToDisplayId = 2; i.replaceTouchableRegionWithCrop = true; i.touchableRegionCropHandle = touchableRegionCropHandle; i.applicationInfo.name = "ApplicationFooBar"; @@ -107,7 +106,6 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.packageName, i2.packageName); ASSERT_EQ(i.inputFeatures, i2.inputFeatures); ASSERT_EQ(i.displayId, i2.displayId); - ASSERT_EQ(i.portalToDisplayId, i2.portalToDisplayId); ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop); ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle); ASSERT_EQ(i.applicationInfo, i2.applicationInfo); -- cgit v1.2.3-59-g8ed1b From 4d5c52ff1615c8cbcfe2f5209884245bba711e7c Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 31 Jan 2022 08:52:10 -0800 Subject: Introduce WindowInfo::InputConfig flag to control input behavior Instead of re-using layoutParams flags and layoutParam types and having redundant information in WindowInfo, we add a new InputConfig flag that the native input pipeline will use for all input window configurations. This also reduces WindowInfo's size by converting booleans into flags. Bug: 216806304 Test: atest libgui_test Test: atest inputflinger_tests Change-Id: If0354cc2cfc84986f7f0d48cd9348be1ff82293d --- libs/gui/WindowInfo.cpp | 59 ++--- libs/gui/include/gui/WindowInfo.h | 48 +++- libs/gui/tests/EndToEndNativeInputTest.cpp | 25 +-- libs/gui/tests/WindowInfo_test.cpp | 18 +- .../benchmarks/InputDispatcher_benchmarks.cpp | 5 - services/inputflinger/dispatcher/FocusResolver.cpp | 4 +- .../inputflinger/dispatcher/InputDispatcher.cpp | 88 ++++---- services/inputflinger/dispatcher/TouchState.cpp | 6 +- services/inputflinger/tests/FocusResolver_test.cpp | 12 +- .../inputflinger/tests/InputDispatcher_test.cpp | 241 ++++++++++++--------- services/surfaceflinger/Layer.cpp | 17 +- services/surfaceflinger/LayerProtoHelper.cpp | 11 +- .../Tracing/TransactionProtoParser.cpp | 23 +- 13 files changed, 320 insertions(+), 237 deletions(-) (limited to 'libs/gui/WindowInfo.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index a8667867b2..2c25e7e2ac 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -18,7 +18,6 @@ #define LOG_TAG "WindowInfo" #define LOG_NDEBUG 0 -#include #include #include @@ -27,6 +26,14 @@ namespace android::gui { // --- WindowInfo --- +void WindowInfo::setInputConfig(Flags config, bool value) { + if (value) { + inputConfig |= config; + return; + } + inputConfig &= ~config; +} + void WindowInfo::addTouchableRegion(const Rect& region) { touchableRegion.orSelf(region); } @@ -40,7 +47,7 @@ bool WindowInfo::frameContainsPoint(int32_t x, int32_t y) const { } bool WindowInfo::supportsSplitTouch() const { - return flags.test(Flag::SPLIT_TOUCH); + return inputConfig.test(InputConfig::SPLIT_TOUCH); } bool WindowInfo::isSpy() const { @@ -58,20 +65,19 @@ bool WindowInfo::overlaps(const WindowInfo* other) const { } bool WindowInfo::operator==(const WindowInfo& info) const { - return info.token == token && info.id == id && info.name == name && info.flags == flags && - info.type == type && info.dispatchingTimeout == dispatchingTimeout && - info.frameLeft == frameLeft && info.frameTop == frameTop && - info.frameRight == frameRight && info.frameBottom == frameBottom && - info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor && - info.transform == transform && info.touchableRegion.hasSameRects(touchableRegion) && - info.visible == visible && info.trustedOverlay == trustedOverlay && - info.focusable == focusable && info.touchOcclusionMode == touchOcclusionMode && - info.hasWallpaper == hasWallpaper && info.paused == paused && - info.ownerPid == ownerPid && info.ownerUid == ownerUid && - info.packageName == packageName && info.inputFeatures == inputFeatures && + return info.token == token && info.id == id && info.name == name && + info.dispatchingTimeout == dispatchingTimeout && info.frameLeft == frameLeft && + info.frameTop == frameTop && info.frameRight == frameRight && + info.frameBottom == frameBottom && info.surfaceInset == surfaceInset && + info.globalScaleFactor == globalScaleFactor && info.transform == transform && + info.touchableRegion.hasSameRects(touchableRegion) && + info.touchOcclusionMode == touchOcclusionMode && info.ownerPid == ownerPid && + info.ownerUid == ownerUid && info.packageName == packageName && + info.inputFeatures == inputFeatures && info.inputConfig == inputConfig && info.displayId == displayId && info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && - info.applicationInfo == applicationInfo; + info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType && + info.layoutParamsFlags == layoutParamsFlags; } status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { @@ -85,13 +91,18 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { } parcel->writeInt32(1); + // Ensure that the size of the flags that we use is 32 bits for writing into the parcel. + static_assert(sizeof(inputFeatures) == 4u); + static_assert(sizeof(inputConfig) == 4u); + // clang-format off status_t status = parcel->writeStrongBinder(token) ?: parcel->writeInt64(dispatchingTimeout.count()) ?: parcel->writeInt32(id) ?: parcel->writeUtf8AsUtf16(name) ?: - parcel->writeInt32(flags.get()) ?: - parcel->writeInt32(static_cast>(type)) ?: + parcel->writeInt32(layoutParamsFlags.get()) ?: + parcel->writeInt32( + static_cast>(layoutParamsType)) ?: parcel->writeInt32(frameLeft) ?: parcel->writeInt32(frameTop) ?: parcel->writeInt32(frameRight) ?: @@ -105,16 +116,12 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeFloat(transform.dtdy()) ?: parcel->writeFloat(transform.dsdy()) ?: parcel->writeFloat(transform.ty()) ?: - parcel->writeBool(visible) ?: - parcel->writeBool(focusable) ?: - parcel->writeBool(hasWallpaper) ?: - parcel->writeBool(paused) ?: - parcel->writeBool(trustedOverlay) ?: parcel->writeInt32(static_cast(touchOcclusionMode)) ?: parcel->writeInt32(ownerPid) ?: parcel->writeInt32(ownerUid) ?: parcel->writeUtf8AsUtf16(packageName) ?: parcel->writeInt32(inputFeatures.get()) ?: + parcel->writeInt32(inputConfig.get()) ?: parcel->writeInt32(displayId) ?: applicationInfo.writeToParcel(parcel) ?: parcel->write(touchableRegion) ?: @@ -141,8 +148,8 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { return status; } - flags = Flags(parcel->readInt32()); - type = static_cast(parcel->readInt32()); + layoutParamsFlags = Flags(parcel->readInt32()); + layoutParamsType = static_cast(parcel->readInt32()); float dsdx, dtdx, tx, dtdy, dsdy, ty; int32_t touchOcclusionModeInt; // clang-format off @@ -159,11 +166,6 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->readFloat(&dtdy) ?: parcel->readFloat(&dsdy) ?: parcel->readFloat(&ty) ?: - parcel->readBool(&visible) ?: - parcel->readBool(&focusable) ?: - parcel->readBool(&hasWallpaper) ?: - parcel->readBool(&paused) ?: - parcel->readBool(&trustedOverlay) ?: parcel->readInt32(&touchOcclusionModeInt) ?: parcel->readInt32(&ownerPid) ?: parcel->readInt32(&ownerUid) ?: @@ -177,6 +179,7 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { touchOcclusionMode = static_cast(touchOcclusionModeInt); inputFeatures = Flags(parcel->readInt32()); + inputConfig = Flags(parcel->readInt32()); // clang-format off status = parcel->readInt32(&displayId) ?: applicationInfo.readFromParcel(parcel) ?: diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index eb64ac9b25..1b3419a25b 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -151,6 +151,34 @@ struct WindowInfo : public Parcelable { // clang-format on }; + // Flags used to determine configuration of this input window. + // Input windows can be configured with two sets of flags: InputFeature (WindowInfo::Feature + // defined above), and InputConfig. When adding a new configuration for an input window: + // - If you are adding a new flag that's visible and accessible to apps, it should be added + // as an InputFeature. + // - If you are adding an internal behaviour that is used within the system or shell and is + // not exposed to apps, it should be added as an InputConfig. + enum class InputConfig : uint32_t { + // clang-format off + NONE = 0, + NOT_VISIBLE = 1 << 0, + NOT_FOCUSABLE = 1 << 1, + NOT_TOUCHABLE = 1 << 2, + NOT_TOUCH_MODAL = 1 << 3, + SPLIT_TOUCH = 1 << 4, + DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 5, + IS_WALLPAPER = 1 << 6, + PAUSE_DISPATCHING = 1 << 7, + // This flag is set when the window is of a trusted type that is allowed to silently + // overlay other windows for the purpose of implementing the secure views feature. + // Trusted overlays, such as IME windows, can partly obscure other windows without causing + // motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. + TRUSTED_OVERLAY = 1 << 8, + WATCH_OUTSIDE_TOUCH = 1 << 9, + SLIPPERY = 1 << 10, + // clang-format on + }; + /* These values are filled in by the WM and passed through SurfaceFlinger * unless specified otherwise. */ @@ -164,8 +192,6 @@ struct WindowInfo : public Parcelable { // This uniquely identifies the input window. int32_t id = -1; std::string name; - Flags flags; - Type type = Type::UNKNOWN; std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5); /* These values are filled in by SurfaceFlinger. */ @@ -198,26 +224,24 @@ struct WindowInfo : public Parcelable { * to absolute coordinates by SurfaceFlinger once the frame is computed. */ Region touchableRegion; - bool visible = false; - bool focusable = false; - bool hasWallpaper = false; - bool paused = false; - /* This flag is set when the window is of a trusted type that is allowed to silently - * overlay other windows for the purpose of implementing the secure views feature. - * Trusted overlays, such as IME windows, can partly obscure other windows without causing - * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - */ - bool trustedOverlay = false; + TouchOcclusionMode touchOcclusionMode = TouchOcclusionMode::BLOCK_UNTRUSTED; int32_t ownerPid = -1; int32_t ownerUid = -1; std::string packageName; Flags inputFeatures; + Flags inputConfig; int32_t displayId = ADISPLAY_ID_NONE; InputApplicationInfo applicationInfo; bool replaceTouchableRegionWithCrop = false; wp touchableRegionCropHandle; + // The window's layout params flags and type set by WM. + Type layoutParamsType = Type::UNKNOWN; + Flags layoutParamsFlags; + + void setInputConfig(Flags config, bool value); + void addTouchableRegion(const Rect& region); bool touchableRegionContainsPoint(int32_t x, int32_t y) const; diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 06a0acae49..1151aa3f0f 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -266,13 +266,10 @@ private: void populateInputInfo(int width, int height) { mInputInfo.token = mClientChannel->getConnectionToken(); mInputInfo.name = "Test info"; - mInputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL; - mInputInfo.type = WindowInfo::Type::BASE_APPLICATION; mInputInfo.dispatchingTimeout = 5s; mInputInfo.globalScaleFactor = 1.0; - mInputInfo.focusable = true; - mInputInfo.hasWallpaper = false; - mInputInfo.paused = false; + mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCH_MODAL, true); + mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, false); mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height)); @@ -750,7 +747,7 @@ TEST_F(InputSurfacesTest, touch_flag_obscured) { // Add non touchable window to fully cover touchable window. Window behind gets touch, but // with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED std::unique_ptr nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); nonTouchableSurface->mInputInfo.ownerUid = 22222; // Overriding occlusion mode otherwise the touch would be discarded at InputDispatcher by // the default obscured/untrusted touch filter introduced in S. @@ -770,8 +767,8 @@ TEST_F(InputSurfacesTest, touch_flag_partially_obscured_with_crop) { // AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED std::unique_ptr parentSurface = makeSurface(100, 100); std::unique_ptr nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; - parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); + parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); nonTouchableSurface->mInputInfo.ownerUid = 22222; parentSurface->mInputInfo.ownerUid = 22222; nonTouchableSurface->showAt(0, 0); @@ -794,8 +791,8 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_crop) { // the touchable window. Window behind gets touch with no obscured flags. std::unique_ptr parentSurface = makeSurface(100, 100); std::unique_ptr nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; - parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); + parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); nonTouchableSurface->mInputInfo.ownerUid = 22222; parentSurface->mInputInfo.ownerUid = 22222; nonTouchableSurface->showAt(0, 0); @@ -815,7 +812,7 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_bql) { std::unique_ptr bufferSurface = InputSurface::makeBufferInputSurface(mComposerClient, 0, 0); - bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); bufferSurface->mInputInfo.ownerUid = 22222; surface->showAt(10, 10); @@ -830,7 +827,7 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) { std::unique_ptr bufferSurface = BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0); - bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); bufferSurface->mInputInfo.ownerUid = 22222; surface->showAt(10, 10); @@ -883,7 +880,7 @@ TEST_F(InputSurfacesTest, strict_unobscured_input_obscured_window) { [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); surface->showAt(100, 100); std::unique_ptr obscuringSurface = makeSurface(100, 100); - obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); obscuringSurface->mInputInfo.ownerUid = 22222; obscuringSurface->showAt(100, 100); injectTap(101, 101); @@ -902,7 +899,7 @@ TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) { [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); surface->showAt(100, 100); std::unique_ptr obscuringSurface = makeSurface(100, 100); - obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); obscuringSurface->mInputInfo.ownerUid = 22222; obscuringSurface->showAt(190, 190); diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index ff3ba2aae0..ff9bae2800 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -49,8 +49,8 @@ TEST(WindowInfo, Parcelling) { i.windowToken = new BBinder(); i.id = 1; i.name = "Foobar"; - i.flags = WindowInfo::Flag::SLIPPERY; - i.type = WindowInfo::Type::INPUT_METHOD; + i.layoutParamsFlags = WindowInfo::Flag::SLIPPERY; + i.layoutParamsType = WindowInfo::Type::INPUT_METHOD; i.dispatchingTimeout = 12s; i.frameLeft = 93; i.frameTop = 34; @@ -60,15 +60,12 @@ TEST(WindowInfo, Parcelling) { i.globalScaleFactor = 0.3; i.alpha = 0.7; i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1}); - i.visible = false; - i.focusable = false; - i.hasWallpaper = false; - i.paused = false; i.touchOcclusionMode = TouchOcclusionMode::ALLOW; i.ownerPid = 19; i.ownerUid = 24; i.packageName = "com.example.package"; i.inputFeatures = WindowInfo::Feature::DISABLE_USER_ACTIVITY; + i.inputConfig = WindowInfo::InputConfig::NOT_FOCUSABLE; i.displayId = 34; i.replaceTouchableRegionWithCrop = true; i.touchableRegionCropHandle = touchableRegionCropHandle; @@ -85,8 +82,8 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.windowToken, i2.windowToken); ASSERT_EQ(i.id, i2.id); ASSERT_EQ(i.name, i2.name); - ASSERT_EQ(i.flags, i2.flags); - ASSERT_EQ(i.type, i2.type); + ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags); + ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType); ASSERT_EQ(i.dispatchingTimeout, i2.dispatchingTimeout); ASSERT_EQ(i.frameLeft, i2.frameLeft); ASSERT_EQ(i.frameTop, i2.frameTop); @@ -96,15 +93,12 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor); ASSERT_EQ(i.alpha, i2.alpha); ASSERT_EQ(i.transform, i2.transform); - ASSERT_EQ(i.visible, i2.visible); - ASSERT_EQ(i.focusable, i2.focusable); - ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper); - ASSERT_EQ(i.paused, i2.paused); ASSERT_EQ(i.touchOcclusionMode, i2.touchOcclusionMode); ASSERT_EQ(i.ownerPid, i2.ownerPid); ASSERT_EQ(i.ownerUid, i2.ownerUid); ASSERT_EQ(i.packageName, i2.packageName); ASSERT_EQ(i.inputFeatures, i2.inputFeatures); + ASSERT_EQ(i.inputConfig, i2.inputConfig); ASSERT_EQ(i.displayId, i2.displayId); ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop); ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle); diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index 41e9ce2e41..cd20a646a7 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -193,7 +193,6 @@ public: void updateInfo() { mInfo.token = mClientChannel->getConnectionToken(); mInfo.name = "FakeWindowHandle"; - mInfo.type = WindowInfo::Type::APPLICATION; mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; mInfo.frameLeft = mFrame.left; mInfo.frameTop = mFrame.top; @@ -202,10 +201,6 @@ public: mInfo.globalScaleFactor = 1.0; mInfo.touchableRegion.clear(); mInfo.addTouchableRegion(mFrame); - mInfo.visible = true; - mInfo.focusable = true; - mInfo.hasWallpaper = false; - mInfo.paused = false; mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = ADISPLAY_ID_DEFAULT; diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp index 600f02ba80..a02b3e8779 100644 --- a/services/inputflinger/dispatcher/FocusResolver.cpp +++ b/services/inputflinger/dispatcher/FocusResolver.cpp @@ -148,11 +148,11 @@ FocusResolver::Focusability FocusResolver::isTokenFocusable( continue; } windowFound = true; - if (window->getInfo()->visible) { + if (!window->getInfo()->inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE)) { // Check if at least a single window is visible. visibleWindowFound = true; } - if (!window->getInfo()->focusable) { + if (window->getInfo()->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE)) { // Check if all windows with the window token are focusable. allWindowsAreFocusable = false; break; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 6c321bcedd..001c50f533 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -500,16 +500,17 @@ bool isUserActivityEvent(const EventEntry& eventEntry) { // Returns true if the given window can accept pointer events at the given display location. bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y, bool isStylus) { - if (windowInfo.displayId != displayId || !windowInfo.visible) { + const auto inputConfig = windowInfo.inputConfig; + if (windowInfo.displayId != displayId || + inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) { return false; } - const auto flags = windowInfo.flags; const bool windowCanInterceptTouch = isStylus && windowInfo.interceptsStylus(); - if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE) && !windowCanInterceptTouch) { + if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) { return false; } - const bool isModalWindow = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) && - !flags.test(WindowInfo::Flag::NOT_TOUCH_MODAL); + const bool isModalWindow = !inputConfig.test(WindowInfo::InputConfig::NOT_FOCUSABLE) && + !inputConfig.test(WindowInfo::InputConfig::NOT_TOUCH_MODAL); if (!isModalWindow && !windowInfo.touchableRegionContainsPoint(x, y)) { return false; } @@ -1047,7 +1048,8 @@ sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayI return windowHandle; } - if (addOutsideTargets && info.flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) { + if (addOutsideTargets && + info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) { touchState->addOrUpdateWindow(windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0)); } @@ -1900,7 +1902,8 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( return InputEventInjectionResult::PERMISSION_DENIED; } - if (focusedWindowHandle->getInfo()->paused) { + if (focusedWindowHandle->getInfo()->inputConfig.test( + WindowInfo::InputConfig::PAUSE_DISPATCHING)) { ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str()); return InputEventInjectionResult::PENDING; } @@ -2101,7 +2104,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( for (const sp& windowHandle : newTouchedWindows) { const WindowInfo& info = *windowHandle->getInfo(); - if (info.paused) { + if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) { ALOGI("Not sending touch event to %s because it is paused", windowHandle->getName().c_str()); continue; @@ -2324,13 +2327,16 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { sp foregroundWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); - if (foregroundWindowHandle && foregroundWindowHandle->getInfo()->hasWallpaper) { + if (foregroundWindowHandle && + foregroundWindowHandle->getInfo()->inputConfig.test( + WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { const std::vector>& windowHandles = getWindowHandlesLocked(displayId); for (const sp& windowHandle : windowHandles) { const WindowInfo* info = windowHandle->getInfo(); if (info->displayId == displayId && - windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) { + windowHandle->getInfo()->inputConfig.test( + WindowInfo::InputConfig::IS_WALLPAPER)) { tempTouchState .addOrUpdateWindow(windowHandle, InputTarget::FLAG_WINDOW_IS_OBSCURED | @@ -2599,9 +2605,10 @@ static bool canBeObscuredBy(const sp& windowHandle, } auto info = windowHandle->getInfo(); auto otherInfo = otherHandle->getInfo(); - if (!otherInfo->visible) { + if (otherInfo->inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) { return false; - } else if (otherInfo->alpha == 0 && otherInfo->flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) { + } else if (otherInfo->alpha == 0 && + otherInfo->inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE)) { // Those act as if they were invisible, so we don't need to flag them. // We do want to potentially flag touchable windows even if they have 0 // opacity, since they can consume touches and alter the effects of the @@ -2613,7 +2620,7 @@ static bool canBeObscuredBy(const sp& windowHandle, // If ownerUid is the same we don't generate occlusion events as there // is no security boundary within an uid. return false; - } else if (otherInfo->trustedOverlay) { + } else if (otherInfo->inputConfig.test(gui::WindowInfo::InputConfig::TRUSTED_OVERLAY)) { return false; } else if (otherInfo->displayId != info->displayId) { return false; @@ -2694,17 +2701,17 @@ InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLo std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info, bool isTouchedWindow) const { return StringPrintf(INDENT2 - "* %stype=%s, package=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, " + "* %spackage=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, " "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32 - "], touchableRegion=%s, window={%s}, flags={%s}, inputFeatures={%s}, " + "], touchableRegion=%s, window={%s}, inputConfig={%s}, inputFeatures={%s}, " "hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n", - isTouchedWindow ? "[TOUCHED] " : "", ftl::enum_string(info->type).c_str(), - info->packageName.c_str(), info->ownerUid, info->id, - toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft, - info->frameTop, info->frameRight, info->frameBottom, - dumpRegion(info->touchableRegion).c_str(), info->name.c_str(), - info->flags.string().c_str(), info->inputFeatures.string().c_str(), - toString(info->token != nullptr), info->applicationInfo.name.c_str(), + isTouchedWindow ? "[TOUCHED] " : "", info->packageName.c_str(), + info->ownerUid, info->id, toString(info->touchOcclusionMode).c_str(), + info->alpha, info->frameLeft, info->frameTop, info->frameRight, + info->frameBottom, dumpRegion(info->touchableRegion).c_str(), + info->name.c_str(), info->inputConfig.string().c_str(), + info->inputFeatures.string().c_str(), toString(info->token != nullptr), + info->applicationInfo.name.c_str(), toString(info->applicationInfo.token).c_str()); } @@ -4572,8 +4579,9 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( if (getInputChannelLocked(handle->getToken()) == nullptr) { const bool noInputChannel = info->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); - const bool canReceiveInput = !info->flags.test(WindowInfo::Flag::NOT_TOUCHABLE) || - !info->flags.test(WindowInfo::Flag::NOT_FOCUSABLE); + const bool canReceiveInput = + !info->inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) || + !info->inputConfig.test(WindowInfo::InputConfig::NOT_FOCUSABLE); if (canReceiveInput && !noInputChannel) { ALOGV("Window handle %s has no registered input channel", handle->getName().c_str()); @@ -4644,12 +4652,16 @@ void InputDispatcher::setInputWindowsLocked( } // Ensure all spy windows are trusted overlays - LOG_ALWAYS_FATAL_IF(info.isSpy() && !info.trustedOverlay, + LOG_ALWAYS_FATAL_IF(info.isSpy() && + !info.inputConfig.test( + WindowInfo::InputConfig::TRUSTED_OVERLAY), "%s has feature SPY, but is not a trusted overlay.", window->getName().c_str()); // Ensure all stylus interceptors are trusted overlays - LOG_ALWAYS_FATAL_IF(info.interceptsStylus() && !info.trustedOverlay, + LOG_ALWAYS_FATAL_IF(info.interceptsStylus() && + !info.inputConfig.test( + WindowInfo::InputConfig::TRUSTED_OVERLAY), "%s has feature INTERCEPTS_STYLUS, but is not a trusted overlay.", window->getName().c_str()); } @@ -4699,7 +4711,8 @@ void InputDispatcher::setInputWindowsLocked( // Since we are about to drop the touch, cancel the events for the wallpaper as // well. if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND && - touchedWindow.windowHandle->getInfo()->hasWallpaper) { + touchedWindow.windowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { sp wallpaper = state.getWallpaperWindow(); if (wallpaper != nullptr) { sp wallpaperConnection = @@ -5194,34 +5207,27 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { const WindowInfo* windowInfo = windowHandle->getInfo(); dump += StringPrintf(INDENT3 "%zu: name='%s', id=%" PRId32 ", displayId=%d, " - "paused=%s, focusable=%s, " - "hasWallpaper=%s, visible=%s, alpha=%.2f, " - "flags=%s, type=%s, " + "inputConfig=%s, alpha=%.2f, " "frame=[%d,%d][%d,%d], globalScale=%f, " "applicationInfo.name=%s, " "applicationInfo.token=%s, " "touchableRegion=", i, windowInfo->name.c_str(), windowInfo->id, - windowInfo->displayId, toString(windowInfo->paused), - toString(windowInfo->focusable), - toString(windowInfo->hasWallpaper), - toString(windowInfo->visible), windowInfo->alpha, - windowInfo->flags.string().c_str(), - ftl::enum_string(windowInfo->type).c_str(), - windowInfo->frameLeft, windowInfo->frameTop, - windowInfo->frameRight, windowInfo->frameBottom, - windowInfo->globalScaleFactor, + windowInfo->displayId, + windowInfo->inputConfig.string().c_str(), + windowInfo->alpha, windowInfo->frameLeft, + windowInfo->frameTop, windowInfo->frameRight, + windowInfo->frameBottom, windowInfo->globalScaleFactor, windowInfo->applicationInfo.name.c_str(), toString(windowInfo->applicationInfo.token).c_str()); dump += dumpRegion(windowInfo->touchableRegion); dump += StringPrintf(", inputFeatures=%s", windowInfo->inputFeatures.string().c_str()); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64 - "ms, trustedOverlay=%s, hasToken=%s, " + "ms, hasToken=%s, " "touchOcclusionMode=%s\n", windowInfo->ownerPid, windowInfo->ownerUid, millis(windowInfo->dispatchingTimeout), - toString(windowInfo->trustedOverlay), toString(windowInfo->token != nullptr), toString(windowInfo->touchOcclusionMode).c_str()); windowInfo->transform.dump(dump, "transform", INDENT4); diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index b63fe104fa..61e78ccbe4 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -100,7 +100,8 @@ bool TouchState::isSlippery() const { for (const TouchedWindow& window : windows) { if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { if (haveSlipperyForegroundWindow || - !window.windowHandle->getInfo()->flags.test(WindowInfo::Flag::SLIPPERY)) { + !window.windowHandle->getInfo()->inputConfig.test( + WindowInfo::InputConfig::SLIPPERY)) { return false; } haveSlipperyForegroundWindow = true; @@ -112,7 +113,8 @@ bool TouchState::isSlippery() const { sp TouchState::getWallpaperWindow() const { for (size_t i = 0; i < windows.size(); i++) { const TouchedWindow& window = windows[i]; - if (window.windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) { + if (window.windowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::IS_WALLPAPER)) { return window.windowHandle; } } diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp index 662be8063e..ffce9f68cc 100644 --- a/services/inputflinger/tests/FocusResolver_test.cpp +++ b/services/inputflinger/tests/FocusResolver_test.cpp @@ -37,12 +37,16 @@ public: bool visible) { mInfo.token = token; mInfo.name = name; - mInfo.visible = visible; - mInfo.focusable = focusable; + setFocusable(focusable); + setVisible(visible); } - void setFocusable(bool focusable) { mInfo.focusable = focusable; } - void setVisible(bool visible) { mInfo.visible = visible; } + void setFocusable(bool focusable) { + mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable); + } + void setVisible(bool visible) { + mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible); + } }; TEST(FocusResolverTest, SetFocusedWindow) { diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 872882e5d8..8b95f28738 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -986,7 +986,6 @@ public: mInfo.token = *token; mInfo.id = sId++; mInfo.name = name; - mInfo.type = WindowInfo::Type::APPLICATION; mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; mInfo.alpha = 1.0; mInfo.frameLeft = 0; @@ -997,14 +996,14 @@ public: mInfo.globalScaleFactor = 1.0; mInfo.touchableRegion.clear(); mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT)); - mInfo.visible = true; - mInfo.focusable = false; - mInfo.hasWallpaper = false; - mInfo.paused = false; mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = displayId; - mInfo.trustedOverlay = false; + setVisible(true); + setFocusable(false); + setDupTouchToWallpaper(false); + setPaused(false); + setTrustedOverlay(false); } sp clone( @@ -1016,15 +1015,41 @@ public: return handle; } - void setFocusable(bool focusable) { mInfo.focusable = focusable; } + void setTouchable(bool touchable) { + mInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, !touchable); + } - void setVisible(bool visible) { mInfo.visible = visible; } + void setFocusable(bool focusable) { + mInfo.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable); + } + + void setVisible(bool visible) { + mInfo.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible); + } void setDispatchingTimeout(std::chrono::nanoseconds timeout) { mInfo.dispatchingTimeout = timeout; } - void setPaused(bool paused) { mInfo.paused = paused; } + void setPaused(bool paused) { + mInfo.setInputConfig(WindowInfo::InputConfig::PAUSE_DISPATCHING, paused); + } + + void setTouchModal(bool touchModal) { + mInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCH_MODAL, !touchModal); + } + + void setSplitTouch(bool splitTouch) { + mInfo.setInputConfig(WindowInfo::InputConfig::SPLIT_TOUCH, splitTouch); + } + + void setSlippery(bool slippery) { + mInfo.setInputConfig(WindowInfo::InputConfig::SLIPPERY, slippery); + } + + void setWatchOutsideTouch(bool watchOutside) { + mInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, watchOutside); + } void setAlpha(float alpha) { mInfo.alpha = alpha; } @@ -1048,17 +1073,19 @@ public: void setTouchableRegion(const Region& region) { mInfo.touchableRegion = region; } - void setType(WindowInfo::Type type) { mInfo.type = type; } - - void setHasWallpaper(bool hasWallpaper) { mInfo.hasWallpaper = hasWallpaper; } - - void addFlags(Flags flags) { mInfo.flags |= flags; } + void setIsWallpaper(bool isWallpaper) { + mInfo.setInputConfig(WindowInfo::InputConfig::IS_WALLPAPER, isWallpaper); + } - void setFlags(Flags flags) { mInfo.flags = flags; } + void setDupTouchToWallpaper(bool hasWallpaper) { + mInfo.setInputConfig(WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER, hasWallpaper); + } void setInputFeatures(Flags features) { mInfo.inputFeatures = features; } - void setTrustedOverlay(bool trustedOverlay) { mInfo.trustedOverlay = trustedOverlay; } + void setTrustedOverlay(bool trustedOverlay) { + mInfo.setInputConfig(WindowInfo::InputConfig::TRUSTED_OVERLAY, trustedOverlay); + } void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) { mInfo.transform.set(dsdx, dtdx, dtdy, dsdy); @@ -1551,7 +1578,7 @@ TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) { sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + window->setTouchModal(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1574,7 +1601,7 @@ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + window->setTouchModal(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -1609,17 +1636,17 @@ TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) { * Two windows: A top window, and a wallpaper behind the window. * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window * gets ACTION_CANCEL. - * 1. foregroundWindow <-- has wallpaper (hasWallpaper=true) - * 2. wallpaperWindow <-- is wallpaper (type=InputWindowInfo::Type::WALLPAPER) + * 1. foregroundWindow <-- dup touch to wallpaper + * 2. wallpaperWindow <-- is wallpaper */ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) { std::shared_ptr application = std::make_shared(); sp foregroundWindow = new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); - foregroundWindow->setHasWallpaper(true); + foregroundWindow->setDupTouchToWallpaper(true); sp wallpaperWindow = new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); - wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; @@ -1660,10 +1687,10 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { std::shared_ptr application = std::make_shared(); sp foregroundWindow = new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); - foregroundWindow->setHasWallpaper(true); + foregroundWindow->setDupTouchToWallpaper(true); sp wallpaperWindow = new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); - wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; @@ -1704,11 +1731,11 @@ TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); - window->setHasWallpaper(true); + window->setDupTouchToWallpaper(true); sp wallpaperWindow = new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); - wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; @@ -1762,19 +1789,21 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { sp leftWindow = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); leftWindow->setFrame(Rect(0, 0, 200, 200)); - leftWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL); - leftWindow->setHasWallpaper(true); + leftWindow->setTouchModal(false); + leftWindow->setSplitTouch(true); + leftWindow->setDupTouchToWallpaper(true); sp rightWindow = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); rightWindow->setFrame(Rect(200, 0, 400, 200)); - rightWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL); - rightWindow->setHasWallpaper(true); + rightWindow->setTouchModal(false); + rightWindow->setSplitTouch(true); + rightWindow->setDupTouchToWallpaper(true); sp wallpaperWindow = new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setFrame(Rect(0, 0, 400, 200)); - wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; @@ -1848,11 +1877,11 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { sp windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + windowLeft->setTouchModal(false); sp windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + windowRight->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -1959,7 +1988,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { sp window = new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 1200, 800)); - window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + window->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -2041,11 +2070,11 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { sp windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + windowLeft->setTouchModal(false); sp windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + windowRight->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -2151,14 +2180,14 @@ public: // Add two windows to the display. Their frames are represented in the display space. sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); - firstWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + firstWindow->setTouchModal(false); firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform); addWindow(firstWindow); sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); - secondWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + secondWindow->setTouchModal(false); secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform); addWindow(secondWindow); return {std::move(firstWindow), std::move(secondWindow)}; @@ -2379,13 +2408,15 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + firstWindow->setTouchModal(false); + firstWindow->setSplitTouch(true); // Create a non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + secondWindow->setTouchModal(false); + secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2451,13 +2482,15 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + firstWindow->setTouchModal(false); + firstWindow->setSplitTouch(true); // Create a non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + secondWindow->setTouchModal(false); + secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2522,26 +2555,26 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { sp firstWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + firstWindowInPrimary->setTouchModal(false); sp secondWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + secondWindowInPrimary->setTouchModal(false); sp mirrorWindowInPrimary = firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); - mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mirrorWindowInPrimary->setTouchModal(false); sp firstWindowInSecondary = firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + firstWindowInSecondary->setTouchModal(false); sp secondWindowInSecondary = secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + secondWindowInPrimary->setTouchModal(false); // Update window info, let it find window handle of second display first. mDispatcher->setInputWindows( @@ -2586,26 +2619,26 @@ TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { sp firstWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + firstWindowInPrimary->setTouchModal(false); sp secondWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + secondWindowInPrimary->setTouchModal(false); sp mirrorWindowInPrimary = firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); - mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mirrorWindowInPrimary->setTouchModal(false); sp firstWindowInSecondary = firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + firstWindowInSecondary->setTouchModal(false); sp secondWindowInSecondary = secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + secondWindowInPrimary->setTouchModal(false); // Update window info, let it find window handle of second display first. mDispatcher->setInputWindows( @@ -2703,13 +2736,15 @@ TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) { sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + firstWindow->setTouchModal(false); + firstWindow->setSplitTouch(true); // Create second non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + secondWindow->setTouchModal(false); + secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -3376,7 +3411,8 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { sp slipperyExitWindow = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); - slipperyExitWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SLIPPERY); + slipperyExitWindow->setTouchModal(false); + slipperyExitWindow->setSlippery(true); // Make sure this one overlaps the bottom window slipperyExitWindow->setFrame(Rect(25, 25, 75, 75)); // Change the owner uid/pid of the window so that it is considered to be occluding the bottom @@ -3984,12 +4020,12 @@ class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. - mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mUnfocusedWindow->setTouchModal(false); mFocusedWindow = new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mFocusedWindow->setTouchModal(false); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -4098,12 +4134,14 @@ class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest { ADISPLAY_ID_DEFAULT); // Adding FLAG_NOT_TOUCH_MODAL otherwise all taps will go to the top most window. // We also need FLAG_SPLIT_TOUCH or we won't be able to get touches for both windows. - mWindow1->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + mWindow1->setTouchModal(false); + mWindow1->setSplitTouch(true); mWindow1->setFrame(Rect(0, 0, 100, 100)); mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2", ADISPLAY_ID_DEFAULT, mWindow1->getToken()); - mWindow2->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + mWindow2->setTouchModal(false); + mWindow2->setSplitTouch(true); mWindow2->setFrame(Rect(100, 100, 200, 200)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}}); @@ -4302,7 +4340,7 @@ class InputDispatcherSingleWindowAnr : public InputDispatcherTest { mWindow->setFocusable(true); // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. - mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mWindow->setTouchModal(false); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -4753,15 +4791,16 @@ class InputDispatcherMultiWindowAnr : public InputDispatcherTest { // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped - mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | - WindowInfo::Flag::WATCH_OUTSIDE_TOUCH | - WindowInfo::Flag::SPLIT_TOUCH); + mUnfocusedWindow->setTouchModal(false); + mUnfocusedWindow->setSplitTouch(true); + mUnfocusedWindow->setWatchOutsideTouch(true); mFocusedWindow = new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT); mFocusedWindow->setDispatchingTimeout(30ms); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + mFocusedWindow->setTouchModal(false); + mFocusedWindow->setSplitTouch(true); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -5495,7 +5534,7 @@ protected: sp getOccludingWindow(int32_t uid, std::string name, TouchOcclusionMode mode, float alpha = 1.0f) { sp window = getWindow(uid, name); - window->setFlags(WindowInfo::Flag::NOT_TOUCHABLE); + window->setTouchable(false); window->setTouchOcclusionMode(mode); window->setAlpha(alpha); return window; @@ -5609,7 +5648,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) { const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); - w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH); + w->setWatchOutsideTouch(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); touch(); @@ -5620,7 +5659,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) { const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); - w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH); + w->setWatchOutsideTouch(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); touch(); @@ -5870,11 +5909,11 @@ protected: mApp = std::make_shared(); mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); mWindow->setFrame(Rect(0, 0, 100, 100)); - mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mWindow->setTouchModal(false); mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); mSecondWindow->setFrame(Rect(100, 0, 200, 100)); - mSecondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mSecondWindow->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}}); @@ -6129,7 +6168,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { ADISPLAY_ID_DEFAULT); obscuringWindow->setFrame(Rect(0, 0, 50, 50)); obscuringWindow->setOwnerInfo(111, 111); - obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE); + obscuringWindow->setTouchable(false); std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); @@ -6175,7 +6214,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) { ADISPLAY_ID_DEFAULT); obscuringWindow->setFrame(Rect(0, 0, 50, 50)); obscuringWindow->setOwnerInfo(111, 111); - obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE); + obscuringWindow->setTouchable(false); std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); @@ -6257,7 +6296,7 @@ TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTou class InputDispatcherSpyWindowTest : public InputDispatcherTest { public: - sp createSpy(const Flags flags) { + sp createSpy() { std::shared_ptr application = std::make_shared(); std::string name = "Fake Spy "; @@ -6266,7 +6305,7 @@ public: new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT); spy->setInputFeatures(WindowInfo::Feature::SPY); spy->setTrustedOverlay(true); - spy->addFlags(flags); + spy->setTouchModal(false); return spy; } @@ -6275,8 +6314,9 @@ public: std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - window->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); window->setFocusable(true); + window->setTouchModal(false); + window->setSplitTouch(true); return window; } @@ -6291,7 +6331,7 @@ using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest; TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) { ScopedSilentDeath _silentDeath; - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy = createSpy(); spy->setTrustedOverlay(false); ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}), ".* not a trusted overlay"); @@ -6301,7 +6341,7 @@ TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) { * Input injection into a display with a spy window but no foreground windows should succeed. */ TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) { - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy = createSpy(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -6324,9 +6364,9 @@ TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) { */ TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) { auto window = createForeground(); - auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); - auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); - auto spy3 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy1 = createSpy(); + auto spy2 = createSpy(); + auto spy3 = createSpy(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window, spy3}}}); const std::vector> channels{spy1, spy2, window, spy3}; const size_t numChannels = channels.size(); @@ -6377,7 +6417,8 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) { */ TEST_F(InputDispatcherSpyWindowTest, NotTouchable) { auto window = createForeground(); - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCHABLE); + auto spy = createSpy(); + spy->setTouchable(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -6394,7 +6435,7 @@ TEST_F(InputDispatcherSpyWindowTest, NotTouchable) { */ TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) { auto window = createForeground(); - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy = createSpy(); spy->setTouchableRegion(Region{{0, 0, 20, 20}}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6425,8 +6466,10 @@ TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) { */ TEST_F(InputDispatcherSpyWindowTest, ModalWindow) { auto window = createForeground(); - auto spy = createSpy(static_cast(0)); - // This spy window does not have the NOT_TOUCH_MODAL flag set. + auto spy = createSpy(); + // Our current policy dictates that modal windows must be focusable. + spy->setFocusable(true); + spy->setTouchModal(true); spy->setFrame(Rect{0, 0, 20, 20}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6445,7 +6488,9 @@ TEST_F(InputDispatcherSpyWindowTest, ModalWindow) { TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { auto window = createForeground(); window->setOwnerInfo(12, 34); - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::WATCH_OUTSIDE_TOUCH); + auto spy = createSpy(); + spy->setWatchOutsideTouch(true); + spy->setTouchModal(false); spy->setOwnerInfo(56, 78); spy->setFrame(Rect{0, 0, 20, 20}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6465,8 +6510,8 @@ TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { */ TEST_F(InputDispatcherSpyWindowTest, PilferPointers) { auto window = createForeground(); - auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); - auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy1 = createSpy(); + auto spy2 = createSpy(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -6498,7 +6543,7 @@ TEST_F(InputDispatcherSpyWindowTest, PilferPointers) { */ TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) { auto window = createForeground(); - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy = createSpy(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -6522,9 +6567,9 @@ TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) { * the spy, but not to any other windows. */ TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) { - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + auto spy = createSpy(); + spy->setTouchModal(false); auto window = createForeground(); - window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6590,7 +6635,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { windowLeft->setFrame({0, 0, 100, 200}); auto windowRight = createForeground(); windowRight->setFrame({100, 0, 200, 200}); - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy = createSpy(); spy->setFrame({0, 0, 200, 200}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, windowLeft, windowRight}}}); @@ -6625,7 +6670,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { auto window = createForeground(); window->setFrame({0, 0, 200, 200}); - auto spyRight = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spyRight = createSpy(); spyRight->setFrame({100, 0, 200, 200}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyRight, window}}}); @@ -6659,14 +6704,15 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { */ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { // Create a touch modal spy that spies on the entire display. - // This spy window does not set the SPLIT_TOUCH flag. However, we still expect to split touches + // This spy window does not set split touch. However, we still expect to split touches // because a foreground window has not disabled splitting. - auto spy = createSpy(static_cast(0)); + auto spy = createSpy(); + spy->setTouchModal(true); + spy->setSplitTouch(false); // Create a non touch modal window that supports split touch. auto window = createForeground(); window->setFrame(Rect(0, 0, 100, 100)); - window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6704,7 +6750,7 @@ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { * do not receive key events. */ TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) { - auto spy = createSpy(static_cast(0)); + auto spy = createSpy(); spy->setFocusable(false); auto window = createForeground(); @@ -6733,7 +6779,8 @@ public: ADISPLAY_ID_DEFAULT); overlay->setFocusable(false); overlay->setOwnerInfo(111, 111); - overlay->setFlags(WindowInfo::Flag::NOT_TOUCHABLE | WindowInfo::Flag::SPLIT_TOUCH); + overlay->setTouchable(false); + overlay->setSplitTouch(true); overlay->setInputFeatures(WindowInfo::Feature::INTERCEPTS_STYLUS); overlay->setTrustedOverlay(true); @@ -6744,7 +6791,7 @@ public: ADISPLAY_ID_DEFAULT); window->setFocusable(true); window->setOwnerInfo(222, 222); - window->setFlags(WindowInfo::Flag::SPLIT_TOUCH); + window->setSplitTouch(true); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index a039250327..d290a76e2f 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2161,8 +2161,8 @@ Rect Layer::getInputBounds() const { void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) { Rect tmpBounds = getInputBounds(); if (!tmpBounds.isValid()) { - info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE; - info.focusable = false; + info.inputConfig |= + WindowInfo::InputConfig::NOT_TOUCH_MODAL | WindowInfo::InputConfig::NOT_FOCUSABLE; info.touchableRegion.clear(); // A layer could have invalid input bounds and still expect to receive touch input if it has // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated @@ -2309,7 +2309,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp mDrawingState.inputInfo.ownerUid = mOwnerUid; mDrawingState.inputInfo.ownerPid = mOwnerPid; mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL; - mDrawingState.inputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL; + mDrawingState.inputInfo.inputConfig |= WindowInfo::InputConfig::NOT_TOUCH_MODAL; mDrawingState.inputInfo.displayId = getLayerStack().id; } @@ -2327,7 +2327,9 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp // We are just using these layers for occlusion detection in // InputDispatcher, and obviously if they aren't visible they can't occlude // anything. - info.visible = hasInputInfo() ? canReceiveInput() : isVisible(); + const bool visible = hasInputInfo() ? canReceiveInput() : isVisible(); + info.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible); + info.alpha = getAlpha(); fillTouchOcclusionMode(info); handleDropInputMode(info); @@ -2349,8 +2351,9 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state // if it was set by WM for a known system overlay - info.trustedOverlay = info.trustedOverlay || isTrustedOverlay(); - + if (isTrustedOverlay()) { + info.inputConfig |= WindowInfo::InputConfig::TRUSTED_OVERLAY; + } // If the layer is a clone, we need to crop the input region to cloned root to prevent // touches from going outside the cloned area. @@ -2482,7 +2485,7 @@ void Layer::updateClonedInputInfo(const std::map, sp>& clonedLa } // Cloned layers shouldn't handle watch outside since their z order is not determined by // WM or the client. - mDrawingState.inputInfo.flags &= ~WindowInfo::Flag::WATCH_OUTSIDE_TOUCH; + mDrawingState.inputInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, false); } void Layer::updateClonedRelatives(const std::map, sp>& clonedLayersMap) { diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index 015caa6a9b..bc06b5cfe8 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -175,12 +175,12 @@ void LayerProtoHelper::writeToProto( } InputWindowInfoProto* proto = getInputWindowInfoProto(); - proto->set_layout_params_flags(inputInfo.flags.get()); + proto->set_layout_params_flags(inputInfo.layoutParamsFlags.get()); using U = std::underlying_type_t; // TODO(b/129481165): This static assert can be safely removed once conversion warnings // are re-enabled. static_assert(std::is_same_v); - proto->set_layout_params_type(static_cast(inputInfo.type)); + proto->set_layout_params_type(static_cast(inputInfo.layoutParamsType)); LayerProtoHelper::writeToProto({inputInfo.frameLeft, inputInfo.frameTop, inputInfo.frameRight, inputInfo.frameBottom}, @@ -189,9 +189,10 @@ void LayerProtoHelper::writeToProto( [&]() { return proto->mutable_touchable_region(); }); proto->set_surface_inset(inputInfo.surfaceInset); - proto->set_visible(inputInfo.visible); - proto->set_focusable(inputInfo.focusable); - proto->set_has_wallpaper(inputInfo.hasWallpaper); + using InputConfig = gui::WindowInfo::InputConfig; + proto->set_visible(!inputInfo.inputConfig.test(InputConfig::NOT_VISIBLE)); + proto->set_focusable(!inputInfo.inputConfig.test(InputConfig::NOT_FOCUSABLE)); + proto->set_has_wallpaper(inputInfo.inputConfig.test(InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)); proto->set_global_scale_factor(inputInfo.globalScaleFactor); LayerProtoHelper::writeToProtoDeprecated(inputInfo.transform, proto->mutable_transform()); diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index a91698fb79..c736d05506 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -183,13 +183,16 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer, if (layer.windowInfoHandle) { const gui::WindowInfo* inputInfo = layer.windowInfoHandle->getInfo(); proto::LayerState_WindowInfo* windowInfoProto = proto.mutable_window_info_handle(); - windowInfoProto->set_layout_params_flags(inputInfo->flags.get()); - windowInfoProto->set_layout_params_type(static_cast(inputInfo->type)); + windowInfoProto->set_layout_params_flags(inputInfo->layoutParamsFlags.get()); + windowInfoProto->set_layout_params_type( + static_cast(inputInfo->layoutParamsType)); LayerProtoHelper::writeToProto(inputInfo->touchableRegion, windowInfoProto->mutable_touchable_region()); windowInfoProto->set_surface_inset(inputInfo->surfaceInset); - windowInfoProto->set_focusable(inputInfo->focusable); - windowInfoProto->set_has_wallpaper(inputInfo->hasWallpaper); + windowInfoProto->set_focusable( + !inputInfo->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE)); + windowInfoProto->set_has_wallpaper(inputInfo->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)); windowInfoProto->set_global_scale_factor(inputInfo->globalScaleFactor); proto::LayerState_Transform* transformProto = windowInfoProto->mutable_transform(); transformProto->set_dsdx(inputInfo->transform.dsdx()); @@ -471,13 +474,17 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, gui::WindowInfo inputInfo; const proto::LayerState_WindowInfo& windowInfoProto = proto.window_info_handle(); - inputInfo.flags = static_cast(windowInfoProto.layout_params_flags()); - inputInfo.type = static_cast(windowInfoProto.layout_params_type()); + inputInfo.layoutParamsFlags = + static_cast(windowInfoProto.layout_params_flags()); + inputInfo.layoutParamsType = + static_cast(windowInfoProto.layout_params_type()); LayerProtoHelper::readFromProto(windowInfoProto.touchable_region(), inputInfo.touchableRegion); inputInfo.surfaceInset = windowInfoProto.surface_inset(); - inputInfo.focusable = windowInfoProto.focusable(); - inputInfo.hasWallpaper = windowInfoProto.has_wallpaper(); + inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE, + !windowInfoProto.focusable()); + inputInfo.setInputConfig(gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER, + windowInfoProto.has_wallpaper()); inputInfo.globalScaleFactor = windowInfoProto.global_scale_factor(); const proto::LayerState_Transform& transformProto = windowInfoProto.transform(); inputInfo.transform.set(transformProto.dsdx(), transformProto.dtdx(), transformProto.dtdy(), -- cgit v1.2.3-59-g8ed1b From 76bdecb09d6a124838edf8495ce90ef4dc0cc3c8 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 31 Jan 2022 11:14:15 -0800 Subject: Invert some InputConfig flags to simplify default behavior Invert NOT_TOUCH_MODAL to TOUCH_MODAL, and SPLIT_TOUCH to PREVENT_SPLITTING. Modal windows and windows that prevent splitting are exceptional behaviors, so we make sure that these show up when outputting flag values using ftl::Flags::string(). Bug: 216806304 Test: atest inputflinger_tests Change-Id: I7cadcc830f06ff0c63da3b61a1a7580cb031f0c2 --- libs/gui/WindowInfo.cpp | 2 +- libs/gui/include/gui/WindowInfo.h | 4 +- libs/gui/tests/EndToEndNativeInputTest.cpp | 3 - .../inputflinger/dispatcher/InputDispatcher.cpp | 5 +- .../inputflinger/tests/InputDispatcher_test.cpp | 105 +++------------------ services/surfaceflinger/Layer.cpp | 6 +- 6 files changed, 20 insertions(+), 105 deletions(-) (limited to 'libs/gui/WindowInfo.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 2c25e7e2ac..80bd6389a0 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -47,7 +47,7 @@ bool WindowInfo::frameContainsPoint(int32_t x, int32_t y) const { } bool WindowInfo::supportsSplitTouch() const { - return inputConfig.test(InputConfig::SPLIT_TOUCH); + return !inputConfig.test(InputConfig::PREVENT_SPLITTING); } bool WindowInfo::isSpy() const { diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 1b3419a25b..c8d49865f0 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -164,8 +164,8 @@ struct WindowInfo : public Parcelable { NOT_VISIBLE = 1 << 0, NOT_FOCUSABLE = 1 << 1, NOT_TOUCHABLE = 1 << 2, - NOT_TOUCH_MODAL = 1 << 3, - SPLIT_TOUCH = 1 << 4, + TOUCH_MODAL = 1 << 3, + PREVENT_SPLITTING = 1 << 4, DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 5, IS_WALLPAPER = 1 << 6, PAUSE_DISPATCHING = 1 << 7, diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 1151aa3f0f..fcfe21bee2 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -268,9 +268,6 @@ private: mInputInfo.name = "Test info"; mInputInfo.dispatchingTimeout = 5s; mInputInfo.globalScaleFactor = 1.0; - mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCH_MODAL, true); - mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, false); - mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height)); InputApplicationInfo aInfo; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index a26256318a..f5aa45b66c 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -509,9 +509,8 @@ bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32 if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) { return false; } - const bool isModalWindow = !inputConfig.test(WindowInfo::InputConfig::NOT_FOCUSABLE) && - !inputConfig.test(WindowInfo::InputConfig::NOT_TOUCH_MODAL); - if (!isModalWindow && !windowInfo.touchableRegionContainsPoint(x, y)) { + if (!inputConfig.test(WindowInfo::InputConfig::TOUCH_MODAL) && + !windowInfo.touchableRegionContainsPoint(x, y)) { return false; } return true; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index da65e176e5..51ecf763a1 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1000,11 +1000,7 @@ public: mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = displayId; - setVisible(true); - setFocusable(false); - setDupTouchToWallpaper(false); - setPaused(false); - setTrustedOverlay(false); + mInfo.inputConfig = WindowInfo::InputConfig::NONE; } sp clone( @@ -1037,11 +1033,11 @@ public: } void setTouchModal(bool touchModal) { - mInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCH_MODAL, !touchModal); + mInfo.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, touchModal); } - void setSplitTouch(bool splitTouch) { - mInfo.setInputConfig(WindowInfo::InputConfig::SPLIT_TOUCH, splitTouch); + void setPreventSplitting(bool preventSplitting) { + mInfo.setInputConfig(WindowInfo::InputConfig::PREVENT_SPLITTING, preventSplitting); } void setSlippery(bool slippery) { @@ -1567,19 +1563,15 @@ TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay } /** - * Calling setInputWindows once with FLAG_NOT_TOUCH_MODAL should not cause any issues. - * To ensure that window receives only events that were directly inside of it, add - * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input - * when finding touched windows. + * Calling setInputWindows once should not cause any issues. * This test serves as a sanity check for the next test, where setInputWindows is * called twice. */ -TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) { +TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setTouchModal(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1593,16 +1585,12 @@ TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) { /** * Calling setInputWindows twice, with the same info, should not cause any issues. - * To ensure that window receives only events that were directly inside of it, add - * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input - * when finding touched windows. */ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setTouchModal(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -1790,15 +1778,11 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { sp leftWindow = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); leftWindow->setFrame(Rect(0, 0, 200, 200)); - leftWindow->setTouchModal(false); - leftWindow->setSplitTouch(true); leftWindow->setDupTouchToWallpaper(true); sp rightWindow = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); rightWindow->setFrame(Rect(200, 0, 400, 200)); - rightWindow->setTouchModal(false); - rightWindow->setSplitTouch(true); rightWindow->setDupTouchToWallpaper(true); sp wallpaperWindow = @@ -1878,11 +1862,9 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { sp windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setTouchModal(false); sp windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -1989,7 +1971,6 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { sp window = new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 1200, 800)); - window->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -2071,11 +2052,9 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { sp windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setTouchModal(false); sp windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -2181,14 +2160,12 @@ public: // Add two windows to the display. Their frames are represented in the display space. sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); - firstWindow->setTouchModal(false); firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform); addWindow(firstWindow); sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); - secondWindow->setTouchModal(false); secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform); addWindow(secondWindow); return {std::move(firstWindow), std::move(secondWindow)}; @@ -2331,8 +2308,10 @@ TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { // Create a couple of windows sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + firstWindow->setPreventSplitting(true); sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); + secondWindow->setPreventSplitting(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2405,19 +2384,13 @@ INSTANTIATE_TEST_SUITE_P(TransferFunctionTests, TransferTouchFixture, TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { std::shared_ptr application = std::make_shared(); - // Create a non touch modal window that supports split touch sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setTouchModal(false); - firstWindow->setSplitTouch(true); - // Create a non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setTouchModal(false); - secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2479,19 +2452,13 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { std::shared_ptr application = std::make_shared(); - // Create a non touch modal window that supports split touch sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setTouchModal(false); - firstWindow->setSplitTouch(true); - // Create a non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setTouchModal(false); - secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2556,26 +2523,21 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { sp firstWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInPrimary->setTouchModal(false); sp secondWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setTouchModal(false); sp mirrorWindowInPrimary = firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); - mirrorWindowInPrimary->setTouchModal(false); sp firstWindowInSecondary = firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInSecondary->setTouchModal(false); sp secondWindowInSecondary = secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setTouchModal(false); // Update window info, let it find window handle of second display first. mDispatcher->setInputWindows( @@ -2620,26 +2582,21 @@ TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { sp firstWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInPrimary->setTouchModal(false); sp secondWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setTouchModal(false); sp mirrorWindowInPrimary = firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); - mirrorWindowInPrimary->setTouchModal(false); sp firstWindowInSecondary = firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInSecondary->setTouchModal(false); sp secondWindowInSecondary = secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setTouchModal(false); // Update window info, let it find window handle of second display first. mDispatcher->setInputWindows( @@ -2733,19 +2690,13 @@ TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) { TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) { std::shared_ptr application = std::make_shared(); - // Create first non touch modal window that supports split touch sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setTouchModal(false); - firstWindow->setSplitTouch(true); - // Create second non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setTouchModal(false); - secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -3265,9 +3216,9 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); + window->setFocusable(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - // Window is not focusable. mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); setFocusedWindow(window); @@ -3275,7 +3226,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) { ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; - // window is invalid, so it should not receive any input event. + // window is not focusable, so it should not receive any input event. window->assertNoEvents(); } @@ -3412,7 +3363,6 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { sp slipperyExitWindow = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); - slipperyExitWindow->setTouchModal(false); slipperyExitWindow->setSlippery(true); // Make sure this one overlaps the bottom window slipperyExitWindow->setFrame(Rect(25, 25, 75, 75)); @@ -4019,14 +3969,10 @@ class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { mUnfocusedWindow = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); - // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this - // window. - mUnfocusedWindow->setTouchModal(false); mFocusedWindow = new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setTouchModal(false); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -4133,16 +4079,10 @@ class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest { std::make_shared(); mWindow1 = new FakeWindowHandle(application, mDispatcher, "Fake Window 1", ADISPLAY_ID_DEFAULT); - // Adding FLAG_NOT_TOUCH_MODAL otherwise all taps will go to the top most window. - // We also need FLAG_SPLIT_TOUCH or we won't be able to get touches for both windows. - mWindow1->setTouchModal(false); - mWindow1->setSplitTouch(true); mWindow1->setFrame(Rect(0, 0, 100, 100)); mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2", ADISPLAY_ID_DEFAULT, mWindow1->getToken()); - mWindow2->setTouchModal(false); - mWindow2->setSplitTouch(true); mWindow2->setFrame(Rect(100, 100, 200, 200)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}}); @@ -4339,9 +4279,6 @@ class InputDispatcherSingleWindowAnr : public InputDispatcherTest { mWindow->setFrame(Rect(0, 0, 30, 30)); mWindow->setDispatchingTimeout(30ms); mWindow->setFocusable(true); - // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this - // window. - mWindow->setTouchModal(false); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -4789,19 +4726,13 @@ class InputDispatcherMultiWindowAnr : public InputDispatcherTest { mUnfocusedWindow = new FakeWindowHandle(mApplication, mDispatcher, "Unfocused", ADISPLAY_ID_DEFAULT); mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); - // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this - // window. // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped - mUnfocusedWindow->setTouchModal(false); - mUnfocusedWindow->setSplitTouch(true); mUnfocusedWindow->setWatchOutsideTouch(true); mFocusedWindow = new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT); mFocusedWindow->setDispatchingTimeout(30ms); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setTouchModal(false); - mFocusedWindow->setSplitTouch(true); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -5910,11 +5841,9 @@ protected: mApp = std::make_shared(); mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); mWindow->setFrame(Rect(0, 0, 100, 100)); - mWindow->setTouchModal(false); mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); mSecondWindow->setFrame(Rect(100, 0, 200, 100)); - mSecondWindow->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}}); @@ -6330,7 +6259,6 @@ public: new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT); spy->setInputFeatures(WindowInfo::Feature::SPY); spy->setTrustedOverlay(true); - spy->setTouchModal(false); return spy; } @@ -6340,8 +6268,6 @@ public: sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); - window->setTouchModal(false); - window->setSplitTouch(true); return window; } @@ -6515,7 +6441,6 @@ TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { window->setOwnerInfo(12, 34); auto spy = createSpy(); spy->setWatchOutsideTouch(true); - spy->setTouchModal(false); spy->setOwnerInfo(56, 78); spy->setFrame(Rect{0, 0, 20, 20}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6593,7 +6518,6 @@ TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) { */ TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) { auto spy = createSpy(); - spy->setTouchModal(false); auto window = createForeground(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6728,14 +6652,11 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { * windows should be allowed to control split touch. */ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { - // Create a touch modal spy that spies on the entire display. - // This spy window does not set split touch. However, we still expect to split touches + // This spy window prevents touch splitting. However, we still expect to split touches // because a foreground window has not disabled splitting. auto spy = createSpy(); - spy->setTouchModal(true); - spy->setSplitTouch(false); + spy->setPreventSplitting(true); - // Create a non touch modal window that supports split touch. auto window = createForeground(); window->setFrame(Rect(0, 0, 100, 100)); @@ -6805,7 +6726,6 @@ public: overlay->setFocusable(false); overlay->setOwnerInfo(111, 111); overlay->setTouchable(false); - overlay->setSplitTouch(true); overlay->setInputFeatures(WindowInfo::Feature::INTERCEPTS_STYLUS); overlay->setTrustedOverlay(true); @@ -6816,7 +6736,6 @@ public: ADISPLAY_ID_DEFAULT); window->setFocusable(true); window->setOwnerInfo(222, 222); - window->setSplitTouch(true); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d0d79e9dd3..219c7164c1 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2159,8 +2159,8 @@ Rect Layer::getInputBounds() const { void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) { Rect tmpBounds = getInputBounds(); if (!tmpBounds.isValid()) { - info.inputConfig |= - WindowInfo::InputConfig::NOT_TOUCH_MODAL | WindowInfo::InputConfig::NOT_FOCUSABLE; + info.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, false); + info.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, true); info.touchableRegion.clear(); // A layer could have invalid input bounds and still expect to receive touch input if it has // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated @@ -2307,7 +2307,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp mDrawingState.inputInfo.ownerUid = mOwnerUid; mDrawingState.inputInfo.ownerPid = mOwnerPid; mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL; - mDrawingState.inputInfo.inputConfig |= WindowInfo::InputConfig::NOT_TOUCH_MODAL; + mDrawingState.inputInfo.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, false); mDrawingState.inputInfo.displayId = getLayerStack().id; } -- cgit v1.2.3-59-g8ed1b From 51e7db07902f5dc7b19f8b45cfc0f2b66764cdda Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 7 Feb 2022 06:02:57 -0800 Subject: WindowInfo: Merge InputConfig and Feature flags Merge the two flags in native code. We move the InputConfig flag defintions to AIDL since we will be using the flags in Java as part of the InputWindowHandle API next. InputFeatureFlags are now a WM-only flag, but is temporarily used by InputWindowHandle until the cleanup is completed. Bug: 216806304 Test: atest libgui_test Test: atest inputflinger_tests Change-Id: I82d6de35b30d9cd4bcaf61499216c8faf407e885 --- libs/gui/WindowInfo.cpp | 10 +- libs/gui/include/gui/WindowInfo.h | 69 +++++----- libs/gui/tests/WindowInfo_test.cpp | 2 - libs/input/Android.bp | 7 +- libs/input/android/os/IInputConstants.aidl | 49 ------- libs/input/android/os/InputConfig.aidl | 147 +++++++++++++++++++++ .../inputflinger/dispatcher/InputDispatcher.cpp | 33 +++-- .../inputflinger/tests/InputDispatcher_test.cpp | 46 ++++--- services/surfaceflinger/Layer.cpp | 16 +-- 9 files changed, 239 insertions(+), 140 deletions(-) create mode 100644 libs/input/android/os/InputConfig.aidl (limited to 'libs/gui/WindowInfo.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 80bd6389a0..b02bae49d3 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -51,11 +51,11 @@ bool WindowInfo::supportsSplitTouch() const { } bool WindowInfo::isSpy() const { - return inputFeatures.test(Feature::SPY); + return inputConfig.test(InputConfig::SPY); } bool WindowInfo::interceptsStylus() const { - return inputFeatures.test(Feature::INTERCEPTS_STYLUS); + return inputConfig.test(InputConfig::INTERCEPTS_STYLUS); } bool WindowInfo::overlaps(const WindowInfo* other) const { @@ -73,8 +73,7 @@ bool WindowInfo::operator==(const WindowInfo& info) const { info.touchableRegion.hasSameRects(touchableRegion) && info.touchOcclusionMode == touchOcclusionMode && info.ownerPid == ownerPid && info.ownerUid == ownerUid && info.packageName == packageName && - info.inputFeatures == inputFeatures && info.inputConfig == inputConfig && - info.displayId == displayId && + info.inputConfig == inputConfig && info.displayId == displayId && info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType && info.layoutParamsFlags == layoutParamsFlags; @@ -92,7 +91,6 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeInt32(1); // Ensure that the size of the flags that we use is 32 bits for writing into the parcel. - static_assert(sizeof(inputFeatures) == 4u); static_assert(sizeof(inputConfig) == 4u); // clang-format off @@ -120,7 +118,6 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeInt32(ownerPid) ?: parcel->writeInt32(ownerUid) ?: parcel->writeUtf8AsUtf16(packageName) ?: - parcel->writeInt32(inputFeatures.get()) ?: parcel->writeInt32(inputConfig.get()) ?: parcel->writeInt32(displayId) ?: applicationInfo.writeToParcel(parcel) ?: @@ -178,7 +175,6 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { touchOcclusionMode = static_cast(touchOcclusionModeInt); - inputFeatures = Flags(parcel->readInt32()); inputConfig = Flags(parcel->readInt32()); // clang-format off status = parcel->readInt32(&displayId) ?: diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index b9bffaa6a0..ef0b98b5cb 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -17,7 +17,7 @@ #pragma once #include -#include +#include #include #include #include @@ -132,49 +132,45 @@ struct WindowInfo : public Parcelable { ftl_last = FIRST_SYSTEM_WINDOW + 15 }; - // This is a conversion of os::IInputConstants::InputFeature to an enum backed by an unsigned + // Flags used to determine configuration of this input window. + // This is a conversion of os::InputConfig to an enum backed by an unsigned // type. This indicates that they are flags, so it can be used with ftl/enum.h. - enum class Feature : uint32_t { + enum class InputConfig : uint32_t { // clang-format off + DEFAULT = + static_cast(os::InputConfig::DEFAULT), NO_INPUT_CHANNEL = - static_cast(os::IInputConstants::InputFeature::NO_INPUT_CHANNEL), + static_cast(os::InputConfig::NO_INPUT_CHANNEL), + NOT_VISIBLE = + static_cast(os::InputConfig::NOT_VISIBLE), + NOT_FOCUSABLE = + static_cast(os::InputConfig::NOT_FOCUSABLE), + NOT_TOUCHABLE = + static_cast(os::InputConfig::NOT_TOUCHABLE), + PREVENT_SPLITTING = + static_cast(os::InputConfig::PREVENT_SPLITTING), + DUPLICATE_TOUCH_TO_WALLPAPER = + static_cast(os::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER), + IS_WALLPAPER = + static_cast(os::InputConfig::IS_WALLPAPER), + PAUSE_DISPATCHING = + static_cast(os::InputConfig::PAUSE_DISPATCHING), + TRUSTED_OVERLAY = + static_cast(os::InputConfig::TRUSTED_OVERLAY), + WATCH_OUTSIDE_TOUCH = + static_cast(os::InputConfig::WATCH_OUTSIDE_TOUCH), + SLIPPERY = + static_cast(os::InputConfig::SLIPPERY), DISABLE_USER_ACTIVITY = - static_cast(os::IInputConstants::InputFeature::DISABLE_USER_ACTIVITY), + static_cast(os::InputConfig::DISABLE_USER_ACTIVITY), DROP_INPUT = - static_cast(os::IInputConstants::InputFeature::DROP_INPUT), + static_cast(os::InputConfig::DROP_INPUT), DROP_INPUT_IF_OBSCURED = - static_cast(os::IInputConstants::InputFeature::DROP_INPUT_IF_OBSCURED), + static_cast(os::InputConfig::DROP_INPUT_IF_OBSCURED), SPY = - static_cast(os::IInputConstants::InputFeature::SPY), + static_cast(os::InputConfig::SPY), INTERCEPTS_STYLUS = - static_cast(os::IInputConstants::InputFeature::INTERCEPTS_STYLUS), - // clang-format on - }; - - // Flags used to determine configuration of this input window. - // Input windows can be configured with two sets of flags: InputFeature (WindowInfo::Feature - // defined above), and InputConfig. When adding a new configuration for an input window: - // - If you are adding a new flag that's visible and accessible to apps, it should be added - // as an InputFeature. - // - If you are adding an internal behaviour that is used within the system or shell and is - // not exposed to apps, it should be added as an InputConfig. - enum class InputConfig : uint32_t { - // clang-format off - NONE = 0, - NOT_VISIBLE = 1 << 0, - NOT_FOCUSABLE = 1 << 1, - NOT_TOUCHABLE = 1 << 2, - PREVENT_SPLITTING = 1 << 3, - DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 4, - IS_WALLPAPER = 1 << 5, - PAUSE_DISPATCHING = 1 << 6, - // This flag is set when the window is of a trusted type that is allowed to silently - // overlay other windows for the purpose of implementing the secure views feature. - // Trusted overlays, such as IME windows, can partly obscure other windows without causing - // motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - TRUSTED_OVERLAY = 1 << 7, - WATCH_OUTSIDE_TOUCH = 1 << 8, - SLIPPERY = 1 << 9, + static_cast(os::InputConfig::INTERCEPTS_STYLUS), // clang-format on }; @@ -228,7 +224,6 @@ struct WindowInfo : public Parcelable { int32_t ownerPid = -1; int32_t ownerUid = -1; std::string packageName; - Flags inputFeatures; Flags inputConfig; int32_t displayId = ADISPLAY_ID_NONE; InputApplicationInfo applicationInfo; diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index ff9bae2800..c51b244c50 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -64,7 +64,6 @@ TEST(WindowInfo, Parcelling) { i.ownerPid = 19; i.ownerUid = 24; i.packageName = "com.example.package"; - i.inputFeatures = WindowInfo::Feature::DISABLE_USER_ACTIVITY; i.inputConfig = WindowInfo::InputConfig::NOT_FOCUSABLE; i.displayId = 34; i.replaceTouchableRegionWithCrop = true; @@ -97,7 +96,6 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.ownerPid, i2.ownerPid); ASSERT_EQ(i.ownerUid, i2.ownerUid); ASSERT_EQ(i.packageName, i2.packageName); - ASSERT_EQ(i.inputFeatures, i2.inputFeatures); ASSERT_EQ(i.inputConfig, i2.inputConfig); ASSERT_EQ(i.displayId, i2.displayId); ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop); diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 930d8194d5..606fe2a59d 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -30,6 +30,7 @@ filegroup { "android/os/IInputConstants.aidl", "android/os/InputEventInjectionResult.aidl", "android/os/InputEventInjectionSync.aidl", + "android/os/InputConfig.aidl", ], } @@ -79,11 +80,8 @@ cc_library { android: { srcs: [ "InputTransport.cpp", - "android/os/BlockUntrustedTouchesMode.aidl", - "android/os/IInputConstants.aidl", "android/os/IInputFlinger.aidl", - "android/os/InputEventInjectionResult.aidl", - "android/os/InputEventInjectionSync.aidl", + ":inputconstants_aidl", ], export_shared_lib_headers: ["libbinder"], @@ -119,6 +117,7 @@ cc_library { "InputTransport.cpp", "android/os/IInputConstants.aidl", "android/os/IInputFlinger.aidl", + "android/os/InputConfig.aidl", ], static_libs: [ "libhostgraphics", diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl index 265cbf0c0b..5ce10a4a50 100644 --- a/libs/input/android/os/IInputConstants.aidl +++ b/libs/input/android/os/IInputConstants.aidl @@ -47,55 +47,6 @@ interface IInputConstants */ const int INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800; - @Backing(type="int") - enum InputFeature { - /** - * Does not construct an input channel for this window. The channel will therefore - * be incapable of receiving input. - */ - NO_INPUT_CHANNEL = 0x00000002, - - /** - * When this window has focus, does not call user activity for all input events so - * the application will have to do it itself. Should only be used by - * the keyguard and phone app. - * - * Should only be used by the keyguard and phone app. - */ - DISABLE_USER_ACTIVITY = 0x00000004, - - /** - * Internal flag used to indicate that input should be dropped on this window. - */ - DROP_INPUT = 0x00000008, - - /** - * Internal flag used to indicate that input should be dropped on this window if this window - * is obscured. - */ - DROP_INPUT_IF_OBSCURED = 0x00000010, - - /** - * An input spy window. This window will receive all pointer events within its touchable - * area, but will will not stop events from being sent to other windows below it in z-order. - * An input event will be dispatched to all spy windows above the top non-spy window at the - * event's coordinates. - */ - SPY = 0x00000020, - - /** - * When used with the window flag {@link #FLAG_NOT_TOUCHABLE}, this window will continue - * to receive events from a stylus device within its touchable region. All other pointer - * events, such as from a mouse or touchscreen, will be dispatched to the windows behind it. - * - * This input feature has no effect when the window flag {@link #FLAG_NOT_TOUCHABLE} is - * not set. - * - * The window must be a trusted overlay to use this input feature. - */ - INTERCEPTS_STYLUS = 0x00000040, - } - /* The default pointer acceleration value. */ const int DEFAULT_POINTER_ACCELERATION = 3; } diff --git a/libs/input/android/os/InputConfig.aidl b/libs/input/android/os/InputConfig.aidl new file mode 100644 index 0000000000..6d1b3967f7 --- /dev/null +++ b/libs/input/android/os/InputConfig.aidl @@ -0,0 +1,147 @@ +/** + * Copyright (c) 2022, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + + +/** + * Input configurations flags used to determine the behavior of input windows. + * @hide + */ +@Backing(type="int") +enum InputConfig { + + /** + * The default InputConfig value with no flags set. + */ + DEFAULT = 0, + + /** + * Does not construct an input channel for this window. The channel will therefore + * be incapable of receiving input. + */ + NO_INPUT_CHANNEL = 1 << 0, + + /** + * Indicates that this input window is not visible, and thus will not be considered as + * an input target and will not obscure other windows. + */ + NOT_VISIBLE = 1 << 1, + + /** + * Indicates that this input window cannot be a focus target, and this will not + * receive any input events that can only be directed for the focused window, such + * as key events. + */ + NOT_FOCUSABLE = 1 << 2, + + /** + * Indicates that this input window cannot receive any events directed at a + * specific location on the screen, such as touchscreen, mouse, and stylus events. + * The window will not be considered as a touch target, but can still obscure other + * windows. + */ + NOT_TOUCHABLE = 1 << 3, + + /** + * Indicates that this window will not accept a touch event that is split between + * more than one window. When set: + * - If this window receives a DOWN event with the first pointer, all successive + * pointers that go down, regardless of their location on the screen, will be + * directed to this window; + * - If the DOWN event lands outside the touchable bounds of this window, no + * successive pointers that go down, regardless of their location on the screen, + * will be directed to this window. + */ + PREVENT_SPLITTING = 1 << 4, + + /** + * Indicates that this window shows the wallpaper behind it, so all touch events + * that it receives should also be sent to the wallpaper. + */ + DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 5, + + /** Indicates that this the wallpaper's input window. */ + IS_WALLPAPER = 1 << 6, + + /** + * Indicates that input events should not be dispatched to this window. When set, + * input events directed towards this window will simply be dropped, and will not + * be dispatched to windows behind it. + */ + PAUSE_DISPATCHING = 1 << 7, + + /** + * This flag is set when the window is of a trusted type that is allowed to silently + * overlay other windows for the purpose of implementing the secure views feature. + * Trusted overlays, such as IME windows, can partly obscure other windows without causing + * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. + */ + TRUSTED_OVERLAY = 1 << 8, + + /** + * Indicates that this window wants to listen for when there is a touch DOWN event + * that occurs outside its touchable bounds. When such an event occurs, this window + * will receive a MotionEvent with ACTION_OUTSIDE. + */ + WATCH_OUTSIDE_TOUCH = 1 << 9, + + /** + * When set, this flag allows touches to leave the current window whenever the finger + * moves above another window. When this happens, the window that touch has just left + * (the current window) will receive ACTION_CANCEL, and the window that touch has entered + * will receive ACTION_DOWN, and the remainder of the touch gesture will only go to the + * new window. Without this flag, the entire gesture is sent to the current window, even + * if the touch leaves the window's bounds. + */ + SLIPPERY = 1 << 10, + + /** + * When this window has focus, does not call user activity for all input events so + * the application will have to do it itself. + */ + DISABLE_USER_ACTIVITY = 1 << 11, + + /** + * Internal flag used to indicate that input should be dropped on this window. + */ + DROP_INPUT = 1 << 12, + + /** + * Internal flag used to indicate that input should be dropped on this window if this window + * is obscured. + */ + DROP_INPUT_IF_OBSCURED = 1 << 13, + + /** + * An input spy window. This window will receive all pointer events within its touchable + * area, but will not stop events from being sent to other windows below it in z-order. + * An input event will be dispatched to all spy windows above the top non-spy window at the + * event's coordinates. + */ + SPY = 1 << 14, + + /** + * When used with {@link #NOT_TOUCHABLE}, this window will continue to receive events from + * a stylus device within its touchable region. All other pointer events, such as from a + * mouse or touchscreen, will be dispatched to the windows behind it. + * + * This configuration has no effect when the config {@link #NOT_TOUCHABLE} is not set. + * + * It is not valid to set this configuration if {@link #TRUSTED_OVERLAY} is not set. + */ + INTERCEPTS_STYLUS = 1 << 15, +} diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 32c3a12a13..7a0022293a 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2698,18 +2698,16 @@ InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLo std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info, bool isTouchedWindow) const { - return StringPrintf(INDENT2 - "* %spackage=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, " - "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32 - "], touchableRegion=%s, window={%s}, inputConfig={%s}, inputFeatures={%s}, " - "hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n", + return StringPrintf(INDENT2 "* %spackage=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, " + "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32 + "], touchableRegion=%s, window={%s}, inputConfig={%s}, " + "hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n", isTouchedWindow ? "[TOUCHED] " : "", info->packageName.c_str(), info->ownerUid, info->id, toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft, info->frameTop, info->frameRight, info->frameBottom, dumpRegion(info->touchableRegion).c_str(), info->name.c_str(), info->inputConfig.string().c_str(), - info->inputFeatures.string().c_str(), toString(info->token != nullptr), - info->applicationInfo.name.c_str(), + toString(info->token != nullptr), info->applicationInfo.name.c_str(), toString(info->applicationInfo.token).c_str()); } @@ -2787,7 +2785,7 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { sp focusedWindowHandle = getFocusedWindowHandleLocked(displayId); if (focusedWindowHandle != nullptr) { const WindowInfo* info = focusedWindowHandle->getInfo(); - if (info->inputFeatures.test(WindowInfo::Feature::DISABLE_USER_ACTIVITY)) { + if (info->inputConfig.test(WindowInfo::InputConfig::DISABLE_USER_ACTIVITY)) { if (DEBUG_DISPATCH_CYCLE) { ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str()); } @@ -4516,7 +4514,7 @@ sp InputDispatcher::getFocusedWindowHandleLocked(int displayId bool InputDispatcher::hasResponsiveConnectionLocked(WindowInfoHandle& windowHandle) const { sp connection = getConnectionLocked(windowHandle.getToken()); const bool noInputChannel = - windowHandle.getInfo()->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); + windowHandle.getInfo()->inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL); if (connection != nullptr && noInputChannel) { ALOGW("%s has feature NO_INPUT_CHANNEL, but it matched to connection %s", windowHandle.getName().c_str(), connection->inputChannel->getName().c_str()); @@ -4566,7 +4564,7 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( const WindowInfo* info = handle->getInfo(); if (getInputChannelLocked(handle->getToken()) == nullptr) { const bool noInputChannel = - info->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); + info->inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL); const bool canReceiveInput = !info->inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) || !info->inputConfig.test(WindowInfo::InputConfig::NOT_FOCUSABLE); @@ -4632,7 +4630,7 @@ void InputDispatcher::setInputWindowsLocked( const WindowInfo& info = *window->getInfo(); // Ensure all tokens are null if the window has feature NO_INPUT_CHANNEL - const bool noInputWindow = info.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); + const bool noInputWindow = info.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL); if (noInputWindow && window->getToken() != nullptr) { ALOGE("%s has feature NO_INPUT_WINDOW, but a non-null token. Clearing", window->getName().c_str()); @@ -5209,8 +5207,6 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { windowInfo->applicationInfo.name.c_str(), toString(windowInfo->applicationInfo.token).c_str()); dump += dumpRegion(windowInfo->touchableRegion); - dump += StringPrintf(", inputFeatures=%s", - windowInfo->inputFeatures.string().c_str()); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64 "ms, hasToken=%s, " "touchOcclusionMode=%s\n", @@ -6248,13 +6244,14 @@ void InputDispatcher::onWindowInfosChanged(const std::vector& window bool InputDispatcher::shouldDropInput( const EventEntry& entry, const sp& windowHandle) const { - if (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT) || - (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED) && + if (windowHandle->getInfo()->inputConfig.test(WindowInfo::InputConfig::DROP_INPUT) || + (windowHandle->getInfo()->inputConfig.test( + WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED) && isWindowObscuredLocked(windowHandle))) { - ALOGW("Dropping %s event targeting %s as requested by input feature %s on display " - "%" PRId32 ".", + ALOGW("Dropping %s event targeting %s as requested by the input configuration {%s} on " + "display %" PRId32 ".", ftl::enum_string(entry.type).c_str(), windowHandle->getName().c_str(), - windowHandle->getInfo()->inputFeatures.string().c_str(), + windowHandle->getInfo()->inputConfig.string().c_str(), windowHandle->getInfo()->displayId); return true; } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index b3f51ee576..b3fea74219 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -991,7 +991,7 @@ public: mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = displayId; - mInfo.inputConfig = WindowInfo::InputConfig::NONE; + mInfo.inputConfig = WindowInfo::InputConfig::DEFAULT; } sp clone( @@ -1035,6 +1035,24 @@ public: mInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, watchOutside); } + void setSpy(bool spy) { mInfo.setInputConfig(WindowInfo::InputConfig::SPY, spy); } + + void setInterceptsStylus(bool interceptsStylus) { + mInfo.setInputConfig(WindowInfo::InputConfig::INTERCEPTS_STYLUS, interceptsStylus); + } + + void setDropInput(bool dropInput) { + mInfo.setInputConfig(WindowInfo::InputConfig::DROP_INPUT, dropInput); + } + + void setDropInputIfObscured(bool dropInputIfObscured) { + mInfo.setInputConfig(WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED, dropInputIfObscured); + } + + void setNoInputChannel(bool noInputChannel) { + mInfo.setInputConfig(WindowInfo::InputConfig::NO_INPUT_CHANNEL, noInputChannel); + } + void setAlpha(float alpha) { mInfo.alpha = alpha; } void setTouchOcclusionMode(TouchOcclusionMode mode) { mInfo.touchOcclusionMode = mode; } @@ -1065,8 +1083,6 @@ public: mInfo.setInputConfig(WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER, hasWallpaper); } - void setInputFeatures(Flags features) { mInfo.inputFeatures = features; } - void setTrustedOverlay(bool trustedOverlay) { mInfo.setInputConfig(WindowInfo::InputConfig::TRUSTED_OVERLAY, trustedOverlay); } @@ -1219,7 +1235,7 @@ public: void assertNoEvents() { if (mInputReceiver == nullptr && - mInfo.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL)) { + mInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) { return; // Can't receive events if the window does not have input channel } ASSERT_NE(nullptr, mInputReceiver) @@ -4301,7 +4317,7 @@ protected: new FakeWindowHandle(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); spy->setTrustedOverlay(true); spy->setFocusable(false); - spy->setInputFeatures(WindowInfo::Feature::SPY); + spy->setSpy(true); spy->setDispatchingTimeout(30ms); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, mWindow}}}); return spy; @@ -5094,7 +5110,7 @@ class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest { "Window without input channel", ADISPLAY_ID_DEFAULT, std::make_optional>(nullptr) /*token*/); - mNoInputWindow->setInputFeatures(WindowInfo::Feature::NO_INPUT_CHANNEL); + mNoInputWindow->setNoInputChannel(true); mNoInputWindow->setFrame(Rect(0, 0, 100, 100)); // It's perfectly valid for this window to not have an associated input channel @@ -5136,7 +5152,7 @@ TEST_F(InputDispatcherMultiWindowOcclusionTests, "Window with input channel and NO_INPUT_CHANNEL", ADISPLAY_ID_DEFAULT); - mNoInputWindow->setInputFeatures(WindowInfo::Feature::NO_INPUT_CHANNEL); + mNoInputWindow->setNoInputChannel(true); mNoInputWindow->setFrame(Rect(0, 0, 100, 100)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mNoInputWindow, mBottomWindow}}}); @@ -6051,7 +6067,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); - window->setInputFeatures(WindowInfo::Feature::DROP_INPUT); + window->setDropInput(true); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -6070,7 +6086,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { window->assertNoEvents(); // With the flag cleared, the window should get input - window->setInputFeatures({}); + window->setDropInput(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); @@ -6096,7 +6112,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); - window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED); + window->setDropInputIfObscured(true); window->setOwnerInfo(222, 222); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); @@ -6116,7 +6132,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { window->assertNoEvents(); // With the flag cleared, the window should get input - window->setInputFeatures({}); + window->setDropInputIfObscured(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); @@ -6142,7 +6158,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); - window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED); + window->setDropInputIfObscured(true); window->setOwnerInfo(222, 222); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); @@ -6251,7 +6267,7 @@ public: name += std::to_string(mSpyCount++); sp spy = new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT); - spy->setInputFeatures(WindowInfo::Feature::SPY); + spy->setSpy(true); spy->setTrustedOverlay(true); return spy; } @@ -6699,7 +6715,7 @@ public: overlay->setFocusable(false); overlay->setOwnerInfo(111, 111); overlay->setTouchable(false); - overlay->setInputFeatures(WindowInfo::Feature::INTERCEPTS_STYLUS); + overlay->setInterceptsStylus(true); overlay->setTrustedOverlay(true); std::shared_ptr application = @@ -6765,7 +6781,7 @@ TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) { TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) { auto [overlay, window] = setupStylusOverlayScenario(); - overlay->setInputFeatures(overlay->getInfo()->inputFeatures | WindowInfo::Feature::SPY); + overlay->setSpy(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); sendStylusEvent(AMOTION_EVENT_ACTION_DOWN); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 533acfdefe..2653d8cb5c 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2251,14 +2251,14 @@ gui::DropInputMode Layer::getDropInputMode() const { } void Layer::handleDropInputMode(gui::WindowInfo& info) const { - if (mDrawingState.inputInfo.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL)) { + if (mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) { return; } // Check if we need to drop input unconditionally gui::DropInputMode dropInputMode = getDropInputMode(); if (dropInputMode == gui::DropInputMode::ALL) { - info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy.", getDebugName()); return; } @@ -2271,7 +2271,7 @@ void Layer::handleDropInputMode(gui::WindowInfo& info) const { // Check if the parent has set an alpha on the layer sp parent = mDrawingParent.promote(); if (parent && parent->getAlpha() != 1.0_hf) { - info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(), static_cast(getAlpha())); } @@ -2279,7 +2279,7 @@ void Layer::handleDropInputMode(gui::WindowInfo& info) const { // Check if the parent has cropped the buffer Rect bufferSize = getCroppedBufferSize(getDrawingState()); if (!bufferSize.isValid()) { - info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED; + info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED; return; } @@ -2291,7 +2291,7 @@ void Layer::handleDropInputMode(gui::WindowInfo& info) const { bool croppedByParent = bufferInScreenSpace != Rect{mScreenBounds}; if (croppedByParent) { - info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy because buffer is cropped by parent", getDebugName()); } else { @@ -2299,7 +2299,7 @@ void Layer::handleDropInputMode(gui::WindowInfo& info) const { // input if the window is obscured. This check should be done in surfaceflinger but the // logic currently resides in inputflinger. So pass the if_obscured check to input to only // drop input events if the window is obscured. - info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED; + info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED; } } @@ -2308,7 +2308,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp mDrawingState.inputInfo.name = getName(); mDrawingState.inputInfo.ownerUid = mOwnerUid; mDrawingState.inputInfo.ownerPid = mOwnerPid; - mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL; + mDrawingState.inputInfo.inputConfig |= WindowInfo::InputConfig::NO_INPUT_CHANNEL; mDrawingState.inputInfo.displayId = getLayerStack().id; } @@ -2336,7 +2336,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp // If the window will be blacked out on a display because the display does not have the secure // flag and the layer has the secure flag set, then drop input. if (!displayIsSecure && isSecure()) { - info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT; } auto cropLayer = mDrawingState.touchableRegionCrop.promote(); -- cgit v1.2.3-59-g8ed1b From 032141ea6963b22047bdbba3983b42010030864d Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 15 Feb 2022 05:30:01 -0800 Subject: WindowInfo: Cleanup reading from parcel Bug: None Test: atest libgui_test Change-Id: Ie5724d990a8a6c1480be3cb1a457920db1c39689 --- libs/gui/WindowInfo.cpp | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) (limited to 'libs/gui/WindowInfo.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index b02bae49d3..2312a8cf0d 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -145,12 +145,14 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { return status; } - layoutParamsFlags = Flags(parcel->readInt32()); - layoutParamsType = static_cast(parcel->readInt32()); float dsdx, dtdx, tx, dtdy, dsdy, ty; - int32_t touchOcclusionModeInt; + int32_t lpFlags, lpType, touchOcclusionModeInt, inputConfigInt; + sp touchableRegionCropHandleSp; + // clang-format off - status = parcel->readInt32(&frameLeft) ?: + status = parcel->readInt32(&lpFlags) ?: + parcel->readInt32(&lpType) ?: + parcel->readInt32(&frameLeft) ?: parcel->readInt32(&frameTop) ?: parcel->readInt32(&frameRight) ?: parcel->readInt32(&frameBottom) ?: @@ -166,32 +168,28 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->readInt32(&touchOcclusionModeInt) ?: parcel->readInt32(&ownerPid) ?: parcel->readInt32(&ownerUid) ?: - parcel->readUtf8FromUtf16(&packageName); - // clang-format on - - if (status != OK) { - return status; - } - - touchOcclusionMode = static_cast(touchOcclusionModeInt); - - inputConfig = Flags(parcel->readInt32()); - // clang-format off - status = parcel->readInt32(&displayId) ?: + parcel->readUtf8FromUtf16(&packageName) ?: + parcel->readInt32(&inputConfigInt) ?: + parcel->readInt32(&displayId) ?: applicationInfo.readFromParcel(parcel) ?: parcel->read(touchableRegion) ?: - parcel->readBool(&replaceTouchableRegionWithCrop); + parcel->readBool(&replaceTouchableRegionWithCrop) ?: + parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?: + parcel->readNullableStrongBinder(&windowToken); // clang-format on if (status != OK) { return status; } - touchableRegionCropHandle = parcel->readStrongBinder(); + layoutParamsFlags = Flags(lpFlags); + layoutParamsType = static_cast(lpType); transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); + touchOcclusionMode = static_cast(touchOcclusionModeInt); + inputConfig = Flags(inputConfigInt); + touchableRegionCropHandle = touchableRegionCropHandleSp; - status = parcel->readNullableStrongBinder(&windowToken); - return status; + return OK; } // --- WindowInfoHandle --- -- cgit v1.2.3-59-g8ed1b From 2f01d772a56167b21b23c8dd4bfaa6cb5f667443 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 23 Mar 2022 16:01:29 -0700 Subject: FTL: Pull Flags into namespace Bug: 185536303 Test: Build Change-Id: Ia9aafc78565414815dfc14732ce85b06fa96e17b --- include/ftl/Flags.h | 225 --------------------- include/ftl/flags.h | 225 +++++++++++++++++++++ libs/ftl/Android.bp | 2 +- libs/ftl/Flags_test.cpp | 213 ------------------- libs/ftl/flags_test.cpp | 214 ++++++++++++++++++++ libs/gui/LayerState.cpp | 2 +- libs/gui/WindowInfo.cpp | 12 +- libs/gui/include/gui/ISurfaceComposer.h | 4 +- libs/gui/include/gui/LayerState.h | 3 +- libs/gui/include/gui/WindowInfo.h | 8 +- services/inputflinger/reader/EventHub.cpp | 14 +- services/inputflinger/reader/InputDevice.cpp | 7 +- services/inputflinger/reader/include/EventHub.h | 22 +- services/inputflinger/reader/include/InputDevice.h | 10 +- .../inputflinger/tests/InputDispatcher_test.cpp | 3 +- services/inputflinger/tests/InputReader_test.cpp | 97 ++++----- .../compositionengine/impl/planner/LayerState.h | 30 +-- .../compositionengine/impl/planner/Predictor.h | 4 +- .../CompositionEngine/src/planner/LayerState.cpp | 8 +- .../CompositionEngine/src/planner/Planner.cpp | 2 +- .../CompositionEngine/src/planner/Predictor.cpp | 2 +- .../tests/planner/LayerStateTest.cpp | 90 ++++----- .../DisplayHardware/VirtualDisplaySurface.cpp | 12 +- services/surfaceflinger/Layer.cpp | 6 +- .../Scheduler/include/scheduler/Features.h | 6 +- .../Tracing/TransactionProtoParser.cpp | 2 +- .../tests/unittests/EventThreadTest.cpp | 3 +- 27 files changed, 620 insertions(+), 606 deletions(-) delete mode 100644 include/ftl/Flags.h create mode 100644 include/ftl/flags.h delete mode 100644 libs/ftl/Flags_test.cpp create mode 100644 libs/ftl/flags_test.cpp (limited to 'libs/gui/WindowInfo.cpp') diff --git a/include/ftl/Flags.h b/include/ftl/Flags.h deleted file mode 100644 index db3d9ea5b9..0000000000 --- a/include/ftl/Flags.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include -#include - -// TODO(b/185536303): Align with FTL style and namespace. - -namespace android { - -/* A class for handling flags defined by an enum or enum class in a type-safe way. */ -template -class Flags { - // F must be an enum or its underlying type is undefined. Theoretically we could specialize this - // further to avoid this restriction but in general we want to encourage the use of enums - // anyways. - static_assert(std::is_enum_v, "Flags type must be an enum"); - using U = std::underlying_type_t; - -public: - constexpr Flags(F f) : mFlags(static_cast(f)) {} - constexpr Flags() : mFlags(0) {} - constexpr Flags(const Flags& f) : mFlags(f.mFlags) {} - - // Provide a non-explicit construct for non-enum classes since they easily convert to their - // underlying types (e.g. when used with bitwise operators). For enum classes, however, we - // should force them to be explicitly constructed from their underlying types to make full use - // of the type checker. - template - constexpr Flags(T t, std::enable_if_t, T>* = nullptr) : mFlags(t) {} - - template - explicit constexpr Flags(T t, std::enable_if_t, T>* = nullptr) - : mFlags(t) {} - - class Iterator { - using Bits = std::uint64_t; - static_assert(sizeof(U) <= sizeof(Bits)); - - public: - constexpr Iterator() = default; - Iterator(Flags flags) : mRemainingFlags(flags.mFlags) { (*this)++; } - - // Pre-fix ++ - Iterator& operator++() { - if (mRemainingFlags.none()) { - mCurrFlag = 0; - } else { - // TODO: Replace with std::countr_zero in C++20. - const Bits bit = static_cast(__builtin_ctzll(mRemainingFlags.to_ullong())); - mRemainingFlags.reset(static_cast(bit)); - mCurrFlag = static_cast(static_cast(1) << bit); - } - return *this; - } - - // Post-fix ++ - Iterator operator++(int) { - Iterator iter = *this; - ++*this; - return iter; - } - - bool operator==(Iterator other) const { - return mCurrFlag == other.mCurrFlag && mRemainingFlags == other.mRemainingFlags; - } - - bool operator!=(Iterator other) const { return !(*this == other); } - - F operator*() const { return F{mCurrFlag}; } - - // iterator traits - - // In the future we could make this a bidirectional const iterator instead of a forward - // iterator but it doesn't seem worth the added complexity at this point. This could not, - // however, be made a non-const iterator as assigning one flag to another is a non-sensical - // operation. - using iterator_category = std::input_iterator_tag; - using value_type = F; - // Per the C++ spec, because input iterators are not assignable the iterator's reference - // type does not actually need to be a reference. In fact, making it a reference would imply - // that modifying it would change the underlying Flags object, which is obviously wrong for - // the same reason this can't be a non-const iterator. - using reference = F; - using difference_type = void; - using pointer = void; - - private: - std::bitset mRemainingFlags; - U mCurrFlag = 0; - }; - - /* - * Tests whether the given flag is set. - */ - bool test(F flag) const { - U f = static_cast(flag); - return (f & mFlags) == f; - } - - /* Tests whether any of the given flags are set */ - bool any(Flags f) const { return (mFlags & f.mFlags) != 0; } - - /* Tests whether all of the given flags are set */ - bool all(Flags f) const { return (mFlags & f.mFlags) == f.mFlags; } - - Flags operator|(Flags rhs) const { return static_cast(mFlags | rhs.mFlags); } - Flags& operator|=(Flags rhs) { - mFlags = mFlags | rhs.mFlags; - return *this; - } - - Flags operator&(Flags rhs) const { return static_cast(mFlags & rhs.mFlags); } - Flags& operator&=(Flags rhs) { - mFlags = mFlags & rhs.mFlags; - return *this; - } - - Flags operator^(Flags rhs) const { return static_cast(mFlags ^ rhs.mFlags); } - Flags& operator^=(Flags rhs) { - mFlags = mFlags ^ rhs.mFlags; - return *this; - } - - Flags operator~() { return static_cast(~mFlags); } - - bool operator==(Flags rhs) const { return mFlags == rhs.mFlags; } - bool operator!=(Flags rhs) const { return !operator==(rhs); } - - Flags& operator=(const Flags& rhs) { - mFlags = rhs.mFlags; - return *this; - } - - inline Flags& clear(Flags f = static_cast(~static_cast(0))) { - return *this &= ~f; - } - - Iterator begin() const { return Iterator(*this); } - - Iterator end() const { return Iterator(); } - - /* - * Returns the stored set of flags. - * - * Note that this returns the underlying type rather than the base enum class. This is because - * the value is no longer necessarily a strict member of the enum since the returned value could - * be multiple enum variants OR'd together. - */ - U get() const { return mFlags; } - - std::string string() const { - std::string result; - bool first = true; - U unstringified = 0; - for (const F f : *this) { - if (const auto flagName = ftl::flag_name(f)) { - appendFlag(result, flagName.value(), first); - } else { - unstringified |= static_cast(f); - } - } - - if (unstringified != 0) { - constexpr auto radix = sizeof(U) == 1 ? ftl::Radix::kBin : ftl::Radix::kHex; - appendFlag(result, ftl::to_string(unstringified, radix), first); - } - - if (first) { - result += "0x0"; - } - - return result; - } - -private: - U mFlags; - - static void appendFlag(std::string& str, const std::string_view& flag, bool& first) { - if (first) { - first = false; - } else { - str += " | "; - } - str += flag; - } -}; - -// This namespace provides operator overloads for enum classes to make it easier to work with them -// as flags. In order to use these, add them via a `using namespace` declaration. -namespace flag_operators { - -template >> -inline Flags operator~(F f) { - return static_cast(~ftl::to_underlying(f)); -} - -template >> -Flags operator|(F lhs, F rhs) { - return static_cast(ftl::to_underlying(lhs) | ftl::to_underlying(rhs)); -} - -} // namespace flag_operators -} // namespace android diff --git a/include/ftl/flags.h b/include/ftl/flags.h new file mode 100644 index 0000000000..70aaa0e6dd --- /dev/null +++ b/include/ftl/flags.h @@ -0,0 +1,225 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +// TODO(b/185536303): Align with FTL style. + +namespace android::ftl { + +/* A class for handling flags defined by an enum or enum class in a type-safe way. */ +template +class Flags { + // F must be an enum or its underlying type is undefined. Theoretically we could specialize this + // further to avoid this restriction but in general we want to encourage the use of enums + // anyways. + static_assert(std::is_enum_v, "Flags type must be an enum"); + using U = std::underlying_type_t; + +public: + constexpr Flags(F f) : mFlags(static_cast(f)) {} + constexpr Flags() : mFlags(0) {} + constexpr Flags(const Flags& f) : mFlags(f.mFlags) {} + + // Provide a non-explicit construct for non-enum classes since they easily convert to their + // underlying types (e.g. when used with bitwise operators). For enum classes, however, we + // should force them to be explicitly constructed from their underlying types to make full use + // of the type checker. + template + constexpr Flags(T t, std::enable_if_t, T>* = nullptr) : mFlags(t) {} + + template + explicit constexpr Flags(T t, std::enable_if_t, T>* = nullptr) + : mFlags(t) {} + + class Iterator { + using Bits = std::uint64_t; + static_assert(sizeof(U) <= sizeof(Bits)); + + public: + constexpr Iterator() = default; + Iterator(Flags flags) : mRemainingFlags(flags.mFlags) { (*this)++; } + + // Pre-fix ++ + Iterator& operator++() { + if (mRemainingFlags.none()) { + mCurrFlag = 0; + } else { + // TODO: Replace with std::countr_zero in C++20. + const Bits bit = static_cast(__builtin_ctzll(mRemainingFlags.to_ullong())); + mRemainingFlags.reset(static_cast(bit)); + mCurrFlag = static_cast(static_cast(1) << bit); + } + return *this; + } + + // Post-fix ++ + Iterator operator++(int) { + Iterator iter = *this; + ++*this; + return iter; + } + + bool operator==(Iterator other) const { + return mCurrFlag == other.mCurrFlag && mRemainingFlags == other.mRemainingFlags; + } + + bool operator!=(Iterator other) const { return !(*this == other); } + + F operator*() const { return F{mCurrFlag}; } + + // iterator traits + + // In the future we could make this a bidirectional const iterator instead of a forward + // iterator but it doesn't seem worth the added complexity at this point. This could not, + // however, be made a non-const iterator as assigning one flag to another is a non-sensical + // operation. + using iterator_category = std::input_iterator_tag; + using value_type = F; + // Per the C++ spec, because input iterators are not assignable the iterator's reference + // type does not actually need to be a reference. In fact, making it a reference would imply + // that modifying it would change the underlying Flags object, which is obviously wrong for + // the same reason this can't be a non-const iterator. + using reference = F; + using difference_type = void; + using pointer = void; + + private: + std::bitset mRemainingFlags; + U mCurrFlag = 0; + }; + + /* + * Tests whether the given flag is set. + */ + bool test(F flag) const { + U f = static_cast(flag); + return (f & mFlags) == f; + } + + /* Tests whether any of the given flags are set */ + bool any(Flags f) const { return (mFlags & f.mFlags) != 0; } + + /* Tests whether all of the given flags are set */ + bool all(Flags f) const { return (mFlags & f.mFlags) == f.mFlags; } + + Flags operator|(Flags rhs) const { return static_cast(mFlags | rhs.mFlags); } + Flags& operator|=(Flags rhs) { + mFlags = mFlags | rhs.mFlags; + return *this; + } + + Flags operator&(Flags rhs) const { return static_cast(mFlags & rhs.mFlags); } + Flags& operator&=(Flags rhs) { + mFlags = mFlags & rhs.mFlags; + return *this; + } + + Flags operator^(Flags rhs) const { return static_cast(mFlags ^ rhs.mFlags); } + Flags& operator^=(Flags rhs) { + mFlags = mFlags ^ rhs.mFlags; + return *this; + } + + Flags operator~() { return static_cast(~mFlags); } + + bool operator==(Flags rhs) const { return mFlags == rhs.mFlags; } + bool operator!=(Flags rhs) const { return !operator==(rhs); } + + Flags& operator=(const Flags& rhs) { + mFlags = rhs.mFlags; + return *this; + } + + inline Flags& clear(Flags f = static_cast(~static_cast(0))) { + return *this &= ~f; + } + + Iterator begin() const { return Iterator(*this); } + + Iterator end() const { return Iterator(); } + + /* + * Returns the stored set of flags. + * + * Note that this returns the underlying type rather than the base enum class. This is because + * the value is no longer necessarily a strict member of the enum since the returned value could + * be multiple enum variants OR'd together. + */ + U get() const { return mFlags; } + + std::string string() const { + std::string result; + bool first = true; + U unstringified = 0; + for (const F f : *this) { + if (const auto flagName = flag_name(f)) { + appendFlag(result, flagName.value(), first); + } else { + unstringified |= static_cast(f); + } + } + + if (unstringified != 0) { + constexpr auto radix = sizeof(U) == 1 ? Radix::kBin : Radix::kHex; + appendFlag(result, to_string(unstringified, radix), first); + } + + if (first) { + result += "0x0"; + } + + return result; + } + +private: + U mFlags; + + static void appendFlag(std::string& str, const std::string_view& flag, bool& first) { + if (first) { + first = false; + } else { + str += " | "; + } + str += flag; + } +}; + +// This namespace provides operator overloads for enum classes to make it easier to work with them +// as flags. In order to use these, add them via a `using namespace` declaration. +namespace flag_operators { + +template >> +inline Flags operator~(F f) { + return static_cast(~to_underlying(f)); +} + +template >> +Flags operator|(F lhs, F rhs) { + return static_cast(to_underlying(lhs) | to_underlying(rhs)); +} + +} // namespace flag_operators +} // namespace android::ftl diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index ef201965ad..c010a2e58a 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -14,11 +14,11 @@ cc_test { address: true, }, srcs: [ - "Flags_test.cpp", "cast_test.cpp", "concat_test.cpp", "enum_test.cpp", "fake_guard_test.cpp", + "flags_test.cpp", "future_test.cpp", "small_map_test.cpp", "small_vector_test.cpp", diff --git a/libs/ftl/Flags_test.cpp b/libs/ftl/Flags_test.cpp deleted file mode 100644 index d241fa272a..0000000000 --- a/libs/ftl/Flags_test.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include - -namespace android::test { - -using namespace android::flag_operators; - -enum class TestFlags : uint8_t { ONE = 0x1, TWO = 0x2, THREE = 0x4 }; - -TEST(Flags, Test) { - Flags flags = TestFlags::ONE; - ASSERT_TRUE(flags.test(TestFlags::ONE)); - ASSERT_FALSE(flags.test(TestFlags::TWO)); - ASSERT_FALSE(flags.test(TestFlags::THREE)); -} - -TEST(Flags, Any) { - Flags flags = TestFlags::ONE | TestFlags::TWO; - ASSERT_TRUE(flags.any(TestFlags::ONE)); - ASSERT_TRUE(flags.any(TestFlags::TWO)); - ASSERT_FALSE(flags.any(TestFlags::THREE)); - ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO)); - ASSERT_TRUE(flags.any(TestFlags::TWO | TestFlags::THREE)); - ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::THREE)); - ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); -} - -TEST(Flags, All) { - Flags flags = TestFlags::ONE | TestFlags::TWO; - ASSERT_TRUE(flags.all(TestFlags::ONE)); - ASSERT_TRUE(flags.all(TestFlags::TWO)); - ASSERT_FALSE(flags.all(TestFlags::THREE)); - ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO)); - ASSERT_FALSE(flags.all(TestFlags::TWO | TestFlags::THREE)); - ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::THREE)); - ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); -} - -TEST(Flags, DefaultConstructor_hasNoFlagsSet) { - Flags flags; - ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); -} - -TEST(Flags, NotOperator_onEmptyFlagsSetsAllFlags) { - Flags flags; - flags = ~flags; - ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); -} - -TEST(Flags, NotOperator_onNonEmptyFlagsInvertsFlags) { - Flags flags = TestFlags::TWO; - flags = ~flags; - ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE)); - ASSERT_FALSE(flags.test(TestFlags::TWO)); -} - -TEST(Flags, OrOperator_withNewFlag) { - Flags flags = TestFlags::ONE; - Flags flags2 = flags | TestFlags::TWO; - ASSERT_FALSE(flags2.test(TestFlags::THREE)); - ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::TWO)); -} - -TEST(Flags, OrOperator_withExistingFlag) { - Flags flags = TestFlags::ONE | TestFlags::THREE; - Flags flags2 = flags | TestFlags::THREE; - ASSERT_FALSE(flags2.test(TestFlags::TWO)); - ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::THREE)); -} - -TEST(Flags, OrEqualsOperator_withNewFlag) { - Flags flags; - flags |= TestFlags::THREE; - ASSERT_TRUE(flags.test(TestFlags::THREE)); - ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO)); -} - -TEST(Flags, OrEqualsOperator_withExistingFlag) { - Flags flags = TestFlags::ONE | TestFlags::THREE; - flags |= TestFlags::THREE; - ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE)); - ASSERT_FALSE(flags.test(TestFlags::TWO)); -} - -TEST(Flags, AndOperator_withOneSetFlag) { - Flags flags = TestFlags::ONE | TestFlags::THREE; - Flags andFlags = flags & TestFlags::THREE; - ASSERT_TRUE(andFlags.test(TestFlags::THREE)); - ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO)); -} - -TEST(Flags, AndOperator_withMultipleSetFlags) { - Flags flags = TestFlags::ONE | TestFlags::THREE; - Flags andFlags = flags & (TestFlags::ONE | TestFlags::THREE); - ASSERT_TRUE(andFlags.all(TestFlags::ONE | TestFlags::THREE)); - ASSERT_FALSE(andFlags.test(TestFlags::TWO)); -} - -TEST(Flags, AndOperator_withNoSetFlags) { - Flags flags = TestFlags::ONE | TestFlags::THREE; - Flags andFlags = flags & TestFlags::TWO; - ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); -} - -TEST(Flags, Equality) { - Flags flags1 = TestFlags::ONE | TestFlags::TWO; - Flags flags2 = TestFlags::ONE | TestFlags::TWO; - ASSERT_EQ(flags1, flags2); -} - -TEST(Flags, Inequality) { - Flags flags1 = TestFlags::ONE | TestFlags::TWO; - Flags flags2 = TestFlags::ONE | TestFlags::THREE; - ASSERT_NE(flags1, flags2); -} - -TEST(Flags, EqualsOperator) { - Flags flags; - flags = TestFlags::ONE; - ASSERT_TRUE(flags.test(TestFlags::ONE)); - ASSERT_FALSE(flags.any(TestFlags::TWO | TestFlags::THREE)); -} - -TEST(Flags, EqualsOperator_DontShareState) { - Flags flags1 = TestFlags::ONE | TestFlags::TWO; - Flags flags2 = flags1; - ASSERT_EQ(flags1, flags2); - - flags1 &= TestFlags::TWO; - ASSERT_NE(flags1, flags2); -} - -TEST(Flags, GetValue) { - Flags flags = TestFlags::ONE | TestFlags::TWO; - ASSERT_EQ(flags.get(), 0x3); -} - -TEST(Flags, String_NoFlags) { - Flags flags; - ASSERT_EQ(flags.string(), "0x0"); -} - -TEST(Flags, String_KnownValues) { - Flags flags = TestFlags::ONE | TestFlags::TWO; - ASSERT_EQ(flags.string(), "ONE | TWO"); -} - -TEST(Flags, String_UnknownValues) { - auto flags = Flags(0b1011); - ASSERT_EQ(flags.string(), "ONE | TWO | 0b1000"); -} - -TEST(FlagsIterator, IteratesOverAllFlags) { - Flags flags1 = TestFlags::ONE | TestFlags::TWO; - Flags flags2; - for (TestFlags f : flags1) { - flags2 |= f; - } - ASSERT_EQ(flags2, flags1); -} - -TEST(FlagsIterator, IteratesInExpectedOrder) { - const std::vector flagOrder = {TestFlags::ONE, TestFlags::TWO}; - Flags flags; - for (TestFlags f : flagOrder) { - flags |= f; - } - - size_t idx = 0; - auto iter = flags.begin(); - while (iter != flags.end() && idx < flagOrder.size()) { - // Make sure the order is what we expect - ASSERT_EQ(*iter, flagOrder[idx]); - iter++; - idx++; - } - ASSERT_EQ(iter, flags.end()); -} -TEST(FlagsIterator, PostFixIncrement) { - Flags flags = TestFlags::ONE | TestFlags::TWO; - auto iter = flags.begin(); - ASSERT_EQ(*(iter++), TestFlags::ONE); - ASSERT_EQ(*iter, TestFlags::TWO); - ASSERT_EQ(*(iter++), TestFlags::TWO); - ASSERT_EQ(iter, flags.end()); -} - -TEST(FlagsIterator, PreFixIncrement) { - Flags flags = TestFlags::ONE | TestFlags::TWO; - auto iter = flags.begin(); - ASSERT_EQ(*++iter, TestFlags::TWO); - ASSERT_EQ(++iter, flags.end()); -} - -} // namespace android::test diff --git a/libs/ftl/flags_test.cpp b/libs/ftl/flags_test.cpp new file mode 100644 index 0000000000..eea052ba33 --- /dev/null +++ b/libs/ftl/flags_test.cpp @@ -0,0 +1,214 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +namespace android::test { + +using ftl::Flags; +using namespace ftl::flag_operators; + +enum class TestFlags : uint8_t { ONE = 0x1, TWO = 0x2, THREE = 0x4 }; + +TEST(Flags, Test) { + Flags flags = TestFlags::ONE; + ASSERT_TRUE(flags.test(TestFlags::ONE)); + ASSERT_FALSE(flags.test(TestFlags::TWO)); + ASSERT_FALSE(flags.test(TestFlags::THREE)); +} + +TEST(Flags, Any) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_TRUE(flags.any(TestFlags::ONE)); + ASSERT_TRUE(flags.any(TestFlags::TWO)); + ASSERT_FALSE(flags.any(TestFlags::THREE)); + ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO)); + ASSERT_TRUE(flags.any(TestFlags::TWO | TestFlags::THREE)); + ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::THREE)); + ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, All) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_TRUE(flags.all(TestFlags::ONE)); + ASSERT_TRUE(flags.all(TestFlags::TWO)); + ASSERT_FALSE(flags.all(TestFlags::THREE)); + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO)); + ASSERT_FALSE(flags.all(TestFlags::TWO | TestFlags::THREE)); + ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, DefaultConstructor_hasNoFlagsSet) { + Flags flags; + ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, NotOperator_onEmptyFlagsSetsAllFlags) { + Flags flags; + flags = ~flags; + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, NotOperator_onNonEmptyFlagsInvertsFlags) { + Flags flags = TestFlags::TWO; + flags = ~flags; + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(flags.test(TestFlags::TWO)); +} + +TEST(Flags, OrOperator_withNewFlag) { + Flags flags = TestFlags::ONE; + Flags flags2 = flags | TestFlags::TWO; + ASSERT_FALSE(flags2.test(TestFlags::THREE)); + ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::TWO)); +} + +TEST(Flags, OrOperator_withExistingFlag) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags flags2 = flags | TestFlags::THREE; + ASSERT_FALSE(flags2.test(TestFlags::TWO)); + ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::THREE)); +} + +TEST(Flags, OrEqualsOperator_withNewFlag) { + Flags flags; + flags |= TestFlags::THREE; + ASSERT_TRUE(flags.test(TestFlags::THREE)); + ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO)); +} + +TEST(Flags, OrEqualsOperator_withExistingFlag) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + flags |= TestFlags::THREE; + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(flags.test(TestFlags::TWO)); +} + +TEST(Flags, AndOperator_withOneSetFlag) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags andFlags = flags & TestFlags::THREE; + ASSERT_TRUE(andFlags.test(TestFlags::THREE)); + ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO)); +} + +TEST(Flags, AndOperator_withMultipleSetFlags) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags andFlags = flags & (TestFlags::ONE | TestFlags::THREE); + ASSERT_TRUE(andFlags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(andFlags.test(TestFlags::TWO)); +} + +TEST(Flags, AndOperator_withNoSetFlags) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags andFlags = flags & TestFlags::TWO; + ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, Equality) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2 = TestFlags::ONE | TestFlags::TWO; + ASSERT_EQ(flags1, flags2); +} + +TEST(Flags, Inequality) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2 = TestFlags::ONE | TestFlags::THREE; + ASSERT_NE(flags1, flags2); +} + +TEST(Flags, EqualsOperator) { + Flags flags; + flags = TestFlags::ONE; + ASSERT_TRUE(flags.test(TestFlags::ONE)); + ASSERT_FALSE(flags.any(TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, EqualsOperator_DontShareState) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2 = flags1; + ASSERT_EQ(flags1, flags2); + + flags1 &= TestFlags::TWO; + ASSERT_NE(flags1, flags2); +} + +TEST(Flags, GetValue) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_EQ(flags.get(), 0x3); +} + +TEST(Flags, String_NoFlags) { + Flags flags; + ASSERT_EQ(flags.string(), "0x0"); +} + +TEST(Flags, String_KnownValues) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_EQ(flags.string(), "ONE | TWO"); +} + +TEST(Flags, String_UnknownValues) { + auto flags = Flags(0b1011); + ASSERT_EQ(flags.string(), "ONE | TWO | 0b1000"); +} + +TEST(FlagsIterator, IteratesOverAllFlags) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2; + for (TestFlags f : flags1) { + flags2 |= f; + } + ASSERT_EQ(flags2, flags1); +} + +TEST(FlagsIterator, IteratesInExpectedOrder) { + const std::vector flagOrder = {TestFlags::ONE, TestFlags::TWO}; + Flags flags; + for (TestFlags f : flagOrder) { + flags |= f; + } + + size_t idx = 0; + auto iter = flags.begin(); + while (iter != flags.end() && idx < flagOrder.size()) { + // Make sure the order is what we expect + ASSERT_EQ(*iter, flagOrder[idx]); + iter++; + idx++; + } + ASSERT_EQ(iter, flags.end()); +} +TEST(FlagsIterator, PostFixIncrement) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + auto iter = flags.begin(); + ASSERT_EQ(*(iter++), TestFlags::ONE); + ASSERT_EQ(*iter, TestFlags::TWO); + ASSERT_EQ(*(iter++), TestFlags::TWO); + ASSERT_EQ(iter, flags.end()); +} + +TEST(FlagsIterator, PreFixIncrement) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + auto iter = flags.begin(); + ASSERT_EQ(*++iter, TestFlags::TWO); + ASSERT_EQ(++iter, flags.end()); +} + +} // namespace android::test diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 34db5b1626..53c7f5ac14 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -815,7 +815,7 @@ status_t BufferData::writeToParcel(Parcel* output) const { status_t BufferData::readFromParcel(const Parcel* input) { int32_t tmpInt32; SAFE_PARCEL(input->readInt32, &tmpInt32); - flags = Flags(tmpInt32); + flags = ftl::Flags(tmpInt32); bool tmpBool = false; SAFE_PARCEL(input->readBool, &tmpBool); diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 2312a8cf0d..804ce4fac0 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -14,10 +14,11 @@ * limitations under the License. */ -#include #define LOG_TAG "WindowInfo" #define LOG_NDEBUG 0 +#include + #include #include @@ -25,8 +26,7 @@ namespace android::gui { -// --- WindowInfo --- -void WindowInfo::setInputConfig(Flags config, bool value) { +void WindowInfo::setInputConfig(ftl::Flags config, bool value) { if (value) { inputConfig |= config; return; @@ -182,18 +182,16 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { return status; } - layoutParamsFlags = Flags(lpFlags); + layoutParamsFlags = ftl::Flags(lpFlags); layoutParamsType = static_cast(lpType); transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); touchOcclusionMode = static_cast(touchOcclusionModeInt); - inputConfig = Flags(inputConfigInt); + inputConfig = ftl::Flags(inputConfigInt); touchableRegionCropHandle = touchableRegionCropHandleSp; return OK; } -// --- WindowInfoHandle --- - WindowInfoHandle::WindowInfoHandle() {} WindowInfoHandle::~WindowInfoHandle() {} diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 0a3cc19a13..b11e6748f0 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -126,7 +126,7 @@ public: frameRateOverride = 1 << 1, }; - using EventRegistrationFlags = Flags; + using EventRegistrationFlags = ftl::Flags; /* * Create a connection with SurfaceFlinger. diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 0f37dab53c..b33d4c0cc3 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -102,7 +103,7 @@ public: // was called with. sp releaseBufferEndpoint; - Flags flags; + ftl::Flags flags; client_cache_t cachedBuffer; diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index ef0b98b5cb..0e1d25812e 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -224,7 +224,7 @@ struct WindowInfo : public Parcelable { int32_t ownerPid = -1; int32_t ownerUid = -1; std::string packageName; - Flags inputConfig; + ftl::Flags inputConfig; int32_t displayId = ADISPLAY_ID_NONE; InputApplicationInfo applicationInfo; bool replaceTouchableRegionWithCrop = false; @@ -232,9 +232,9 @@ struct WindowInfo : public Parcelable { // The window's layout params flags and type set by WM. Type layoutParamsType = Type::UNKNOWN; - Flags layoutParamsFlags; + ftl::Flags layoutParamsFlags; - void setInputConfig(Flags config, bool value); + void setInputConfig(ftl::Flags config, bool value); void addTouchableRegion(const Rect& region); diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 8bd3899469..d6a6bd214e 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -60,10 +60,11 @@ #define INDENT3 " " using android::base::StringPrintf; -using namespace android::flag_operators; namespace android { +using namespace ftl::flag_operators; + static const char* DEVICE_INPUT_PATH = "/dev/input"; // v4l2 devices go directly into /dev static const char* DEVICE_PATH = "/dev"; @@ -302,7 +303,8 @@ static std::optional> getColorIndexArray( // --- Global Functions --- -Flags getAbsAxisUsage(int32_t axis, Flags deviceClasses) { +ftl::Flags getAbsAxisUsage(int32_t axis, + ftl::Flags deviceClasses) { // Touch devices get dibs on touch-related axes. if (deviceClasses.test(InputDeviceClass::TOUCH)) { switch (axis) { @@ -765,10 +767,10 @@ InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const { return device != nullptr ? device->identifier : InputDeviceIdentifier(); } -Flags EventHub::getDeviceClasses(int32_t deviceId) const { +ftl::Flags EventHub::getDeviceClasses(int32_t deviceId) const { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); - return device != nullptr ? device->classes : Flags(0); + return device != nullptr ? device->classes : ftl::Flags(0); } int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const { @@ -1909,7 +1911,7 @@ void EventHub::unregisterVideoDeviceFromEpollLocked(const TouchVideoDevice& vide } void EventHub::reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier, - Flags classes) { + ftl::Flags classes) { SHA256_CTX ctx; SHA256_Init(&ctx); SHA256_Update(&ctx, reinterpret_cast(identifier.uniqueId.c_str()), @@ -2191,7 +2193,7 @@ void EventHub::openDeviceLocked(const std::string& devicePath) { } // If the device isn't recognized as something we handle, don't monitor it. - if (device->classes == Flags(0)) { + if (device->classes == ftl::Flags(0)) { ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath.c_str(), device->identifier.name.c_str()); return; diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index a050963fef..ba5083bec3 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -18,9 +18,10 @@ #include "InputDevice.h" -#include #include +#include + #include "CursorInputMapper.h" #include "ExternalStylusInputMapper.h" #include "InputReaderContext.h" @@ -145,7 +146,7 @@ void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) { return; } std::unique_ptr contextPtr(new InputDeviceContext(*this, eventHubId)); - Flags classes = contextPtr->getDeviceClasses(); + ftl::Flags classes = contextPtr->getDeviceClasses(); std::vector> mappers; // Check if we should skip population @@ -236,7 +237,7 @@ void InputDevice::removeEventHubDevice(int32_t eventHubId) { void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { mSources = 0; - mClasses = Flags(0); + mClasses = ftl::Flags(0); mControllerNumber = 0; for_each_subdevice([this](InputDeviceContext& context) { diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 18e912db75..130c55639b 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -19,13 +19,12 @@ #include #include +#include #include #include -#include -#include - #include +#include #include #include #include @@ -189,7 +188,7 @@ struct RawLightInfo { int32_t id; std::string name; std::optional maxBrightness; - Flags flags; + ftl::Flags flags; std::array rgbIndex; std::filesystem::path path; }; @@ -198,7 +197,7 @@ struct RawLightInfo { struct RawBatteryInfo { int32_t id; std::string name; - Flags flags; + ftl::Flags flags; std::filesystem::path path; }; @@ -206,7 +205,8 @@ struct RawBatteryInfo { * Gets the class that owns an axis, in cases where multiple classes might claim * the same axis for different purposes. */ -extern Flags getAbsAxisUsage(int32_t axis, Flags deviceClasses); +extern ftl::Flags getAbsAxisUsage(int32_t axis, + ftl::Flags deviceClasses); /* * Grand Central Station for events. @@ -239,7 +239,7 @@ public: FIRST_SYNTHETIC_EVENT = DEVICE_ADDED, }; - virtual Flags getDeviceClasses(int32_t deviceId) const = 0; + virtual ftl::Flags getDeviceClasses(int32_t deviceId) const = 0; virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0; @@ -436,7 +436,7 @@ class EventHub : public EventHubInterface { public: EventHub(); - Flags getDeviceClasses(int32_t deviceId) const override final; + ftl::Flags getDeviceClasses(int32_t deviceId) const override final; InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override final; @@ -559,7 +559,7 @@ private: std::unique_ptr videoDevice; - Flags classes; + ftl::Flags classes; BitArray keyBitmask; BitArray keyState; @@ -662,7 +662,7 @@ private: int32_t getNextControllerNumberLocked(const std::string& name) REQUIRES(mLock); void releaseControllerNumberLocked(int32_t num) REQUIRES(mLock); void reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier, - Flags classes) REQUIRES(mLock); + ftl::Flags classes) REQUIRES(mLock); const std::unordered_map& getBatteryInfoLocked(int32_t deviceId) const REQUIRES(mLock); @@ -725,6 +725,6 @@ private: bool mPendingINotify; }; -}; // namespace android +} // namespace android #endif // _RUNTIME_EVENT_HUB_H diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 694daa99ce..728020eadc 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -17,12 +17,12 @@ #ifndef _UI_INPUTREADER_INPUT_DEVICE_H #define _UI_INPUTREADER_INPUT_DEVICE_H -#include +#include #include #include #include -#include +#include #include #include #include @@ -53,7 +53,7 @@ public: inline int32_t getGeneration() const { return mGeneration; } inline const std::string getName() const { return mIdentifier.name; } inline const std::string getDescriptor() { return mIdentifier.descriptor; } - inline Flags getClasses() const { return mClasses; } + inline ftl::Flags getClasses() const { return mClasses; } inline uint32_t getSources() const { return mSources; } inline bool hasEventHubDevices() const { return !mDevices.empty(); } @@ -160,7 +160,7 @@ private: int32_t mControllerNumber; InputDeviceIdentifier mIdentifier; std::string mAlias; - Flags mClasses; + ftl::Flags mClasses; // map from eventHubId to device context and mappers using MapperVector = std::vector>; @@ -250,7 +250,7 @@ public: inline int32_t getId() { return mDeviceId; } inline int32_t getEventHubId() { return mId; } - inline Flags getDeviceClasses() const { + inline ftl::Flags getDeviceClasses() const { return mEventHub->getDeviceClasses(mId); } inline InputDeviceIdentifier getDeviceIdentifier() const { diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index bf587050c6..864128734b 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -39,10 +39,11 @@ using android::gui::WindowInfo; using android::gui::WindowInfoHandle; using android::os::InputEventInjectionResult; using android::os::InputEventInjectionSync; -using namespace android::flag_operators; namespace android::inputdispatcher { +using namespace ftl::flag_operators; + // An arbitrary time value. static const nsecs_t ARBITRARY_TIME = 1234; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 9f33d23af5..8ba501c275 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +#include +#include + #include #include #include @@ -34,18 +37,15 @@ #include #include #include -#include -#include -#include -#include #include "input/DisplayViewport.h" #include "input/Input.h" namespace android { +using namespace ftl::flag_operators; + using std::chrono_literals::operator""ms; -using namespace android::flag_operators; // Timeout for waiting for an expected event static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms; @@ -429,7 +429,7 @@ class FakeEventHub : public EventHubInterface { struct Device { InputDeviceIdentifier identifier; - Flags classes; + ftl::Flags classes; PropertyMap configuration; KeyedVector absoluteAxes; KeyedVector relativeAxes; @@ -457,7 +457,7 @@ class FakeEventHub : public EventHubInterface { return OK; } - explicit Device(Flags classes) : classes(classes), enabled(true) {} + explicit Device(ftl::Flags classes) : classes(classes), enabled(true) {} }; std::mutex mLock; @@ -484,7 +484,8 @@ public: FakeEventHub() { } - void addDevice(int32_t deviceId, const std::string& name, Flags classes) { + void addDevice(int32_t deviceId, const std::string& name, + ftl::Flags classes) { Device* device = new Device(classes); device->identifier.name = name; mDevices.add(deviceId, device); @@ -695,9 +696,9 @@ private: return index >= 0 ? mDevices.valueAt(index) : nullptr; } - Flags getDeviceClasses(int32_t deviceId) const override { + ftl::Flags getDeviceClasses(int32_t deviceId) const override { Device* device = getDevice(deviceId); - return device ? device->classes : Flags(0); + return device ? device->classes : ftl::Flags(0); } InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override { @@ -1572,8 +1573,8 @@ protected: mFakePolicy.clear(); } - void addDevice(int32_t eventHubId, const std::string& name, Flags classes, - const PropertyMap* configuration) { + void addDevice(int32_t eventHubId, const std::string& name, + ftl::Flags classes, const PropertyMap* configuration) { mFakeEventHub->addDevice(eventHubId, name, classes); if (configuration) { @@ -1598,7 +1599,8 @@ protected: FakeInputMapper& addDeviceWithFakeInputMapper(int32_t deviceId, int32_t eventHubId, const std::string& name, - Flags classes, uint32_t sources, + ftl::Flags classes, + uint32_t sources, const PropertyMap* configuration) { std::shared_ptr device = mReader->newDevice(deviceId, name); FakeInputMapper& mapper = device->addMapper(eventHubId, sources); @@ -1610,7 +1612,7 @@ protected: TEST_F(InputReaderTest, PolicyGetInputDevices) { ASSERT_NO_FATAL_FAILURE(addDevice(1, "keyboard", InputDeviceClass::KEYBOARD, nullptr)); - ASSERT_NO_FATAL_FAILURE(addDevice(2, "ignored", Flags(0), + ASSERT_NO_FATAL_FAILURE(addDevice(2, "ignored", ftl::Flags(0), nullptr)); // no classes so device will be ignored // Should also have received a notification describing the new input devices. @@ -1672,7 +1674,7 @@ TEST_F(InputReaderTest, GetMergedInputDevicesEnabled) { TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass(InputDeviceClass::KEYBOARD); + constexpr ftl::Flags deviceClass(InputDeviceClass::KEYBOARD); constexpr int32_t eventHubId = 1; std::shared_ptr device = mReader->newDevice(deviceId, "fake"); // Must add at least one mapper or the device will be ignored! @@ -1709,7 +1711,7 @@ TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) { TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; FakeInputMapper& mapper = addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass, @@ -1773,7 +1775,7 @@ TEST_F(InputReaderTest, GetKeyCodeForKeyLocation_NoKeyboardMapper) { TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; FakeInputMapper& mapper = addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass, @@ -1806,7 +1808,7 @@ TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; FakeInputMapper& mapper = addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass, @@ -1839,7 +1841,7 @@ TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; FakeInputMapper& mapper = addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass, @@ -1891,7 +1893,7 @@ TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChange TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr nsecs_t when = 0; constexpr int32_t eventHubId = 1; constexpr nsecs_t readTime = 2; @@ -1915,7 +1917,7 @@ TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { TEST_F(InputReaderTest, DeviceReset_RandomId) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; std::shared_ptr device = mReader->newDevice(deviceId, "fake"); // Must add at least one mapper or the device will be ignored! @@ -1948,7 +1950,7 @@ TEST_F(InputReaderTest, DeviceReset_RandomId) { TEST_F(InputReaderTest, DeviceReset_GenerateIdWithInputReaderSource) { constexpr int32_t deviceId = 1; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; std::shared_ptr device = mReader->newDevice(deviceId, "fake"); // Must add at least one mapper or the device will be ignored! @@ -1963,7 +1965,7 @@ TEST_F(InputReaderTest, DeviceReset_GenerateIdWithInputReaderSource) { TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "USB1"; std::shared_ptr device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); @@ -2008,7 +2010,7 @@ TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { TEST_F(InputReaderTest, WhenEnabledChanges_AllSubdevicesAreUpdated) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1}; std::shared_ptr device = mReader->newDevice(deviceId, "fake"); // Must add at least one mapper or the device will be ignored! @@ -2049,7 +2051,7 @@ TEST_F(InputReaderTest, WhenEnabledChanges_AllSubdevicesAreUpdated) { TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToSubdeviceMappers) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1}; // Add two subdevices to device std::shared_ptr device = mReader->newDevice(deviceId, "fake"); @@ -2106,7 +2108,8 @@ public: TEST_F(InputReaderTest, VibratorGetVibratorIds) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - Flags deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::VIBRATOR; + ftl::Flags deviceClass = + InputDeviceClass::KEYBOARD | InputDeviceClass::VIBRATOR; constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "BLUETOOTH"; std::shared_ptr device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); @@ -2166,7 +2169,8 @@ private: TEST_F(InputReaderTest, BatteryGetCapacity) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - Flags deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY; + ftl::Flags deviceClass = + InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY; constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "BLUETOOTH"; std::shared_ptr device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); @@ -2182,7 +2186,8 @@ TEST_F(InputReaderTest, BatteryGetCapacity) { TEST_F(InputReaderTest, BatteryGetStatus) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - Flags deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY; + ftl::Flags deviceClass = + InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY; constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "BLUETOOTH"; std::shared_ptr device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); @@ -2198,7 +2203,7 @@ TEST_F(InputReaderTest, BatteryGetStatus) { TEST_F(InputReaderTest, LightGetColor) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - Flags deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT; + ftl::Flags deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT; constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "BLUETOOTH"; std::shared_ptr device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); @@ -2625,7 +2630,7 @@ protected: static const int32_t DEVICE_ID; static const int32_t DEVICE_GENERATION; static const int32_t DEVICE_CONTROLLER_NUMBER; - static const Flags DEVICE_CLASSES; + static const ftl::Flags DEVICE_CLASSES; static const int32_t EVENTHUB_ID; std::shared_ptr mFakeEventHub; @@ -2646,7 +2651,7 @@ protected: mDevice = std::make_shared(mReader->getContext(), DEVICE_ID, DEVICE_GENERATION, identifier); mReader->pushNextDevice(mDevice); - mFakeEventHub->addDevice(EVENTHUB_ID, DEVICE_NAME, Flags(0)); + mFakeEventHub->addDevice(EVENTHUB_ID, DEVICE_NAME, ftl::Flags(0)); mReader->loopOnce(); } @@ -2661,14 +2666,14 @@ const char* InputDeviceTest::DEVICE_LOCATION = "USB1"; const int32_t InputDeviceTest::DEVICE_ID = END_RESERVED_ID + 1000; const int32_t InputDeviceTest::DEVICE_GENERATION = 2; const int32_t InputDeviceTest::DEVICE_CONTROLLER_NUMBER = 0; -const Flags InputDeviceTest::DEVICE_CLASSES = +const ftl::Flags InputDeviceTest::DEVICE_CLASSES = InputDeviceClass::KEYBOARD | InputDeviceClass::TOUCH | InputDeviceClass::JOYSTICK; const int32_t InputDeviceTest::EVENTHUB_ID = 1; TEST_F(InputDeviceTest, ImmutableProperties) { ASSERT_EQ(DEVICE_ID, mDevice->getId()); ASSERT_STREQ(DEVICE_NAME, mDevice->getName().c_str()); - ASSERT_EQ(Flags(0), mDevice->getClasses()); + ASSERT_EQ(ftl::Flags(0), mDevice->getClasses()); } TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsFalse) { @@ -2912,7 +2917,7 @@ protected: static const int32_t DEVICE_ID; static const int32_t DEVICE_GENERATION; static const int32_t DEVICE_CONTROLLER_NUMBER; - static const Flags DEVICE_CLASSES; + static const ftl::Flags DEVICE_CLASSES; static const int32_t EVENTHUB_ID; std::shared_ptr mFakeEventHub; @@ -2921,7 +2926,7 @@ protected: std::unique_ptr mReader; std::shared_ptr mDevice; - virtual void SetUp(Flags classes) { + virtual void SetUp(ftl::Flags classes) { mFakeEventHub = std::make_unique(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = std::make_unique(); @@ -2953,7 +2958,7 @@ protected: std::shared_ptr newDevice(int32_t deviceId, const std::string& name, const std::string& location, int32_t eventHubId, - Flags classes) { + ftl::Flags classes) { InputDeviceIdentifier identifier; identifier.name = name; identifier.location = location; @@ -3045,8 +3050,8 @@ const char* InputMapperTest::DEVICE_LOCATION = "USB1"; const int32_t InputMapperTest::DEVICE_ID = END_RESERVED_ID + 1000; const int32_t InputMapperTest::DEVICE_GENERATION = 2; const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0; -const Flags InputMapperTest::DEVICE_CLASSES = - Flags(0); // not needed for current tests +const ftl::Flags InputMapperTest::DEVICE_CLASSES = + ftl::Flags(0); // not needed for current tests const int32_t InputMapperTest::EVENTHUB_ID = 1; // --- SwitchInputMapperTest --- @@ -3842,7 +3847,7 @@ TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) { constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1; std::shared_ptr device2 = newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID, - Flags(0)); + ftl::Flags(0)); mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); @@ -3954,7 +3959,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleAfterReattach) { constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1; std::shared_ptr device2 = newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID, - Flags(0)); + ftl::Flags(0)); mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_CAPSL, true /*initially on*/); mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_NUML, false /*initially off*/); mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_SCROLLL, false /*initially off*/); @@ -8409,7 +8414,7 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) { constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1; std::shared_ptr device2 = newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID, - Flags(0)); + ftl::Flags(0)); mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0 /*flat*/, 0 /*fuzz*/); @@ -9350,7 +9355,7 @@ protected: static const int32_t DEVICE_ID; static const int32_t DEVICE_GENERATION; static const int32_t DEVICE_CONTROLLER_NUMBER; - static const Flags DEVICE_CLASSES; + static const ftl::Flags DEVICE_CLASSES; static const int32_t EVENTHUB_ID; std::shared_ptr mFakeEventHub; @@ -9359,7 +9364,7 @@ protected: std::unique_ptr mReader; std::shared_ptr mDevice; - virtual void SetUp(Flags classes) { + virtual void SetUp(ftl::Flags classes) { mFakeEventHub = std::make_unique(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = std::make_unique(); @@ -9385,7 +9390,7 @@ protected: std::shared_ptr newDevice(int32_t deviceId, const std::string& name, const std::string& location, int32_t eventHubId, - Flags classes) { + ftl::Flags classes) { InputDeviceIdentifier identifier; identifier.name = name; identifier.location = location; @@ -9411,8 +9416,8 @@ const char* PeripheralControllerTest::DEVICE_LOCATION = "BLUETOOTH"; const int32_t PeripheralControllerTest::DEVICE_ID = END_RESERVED_ID + 1000; const int32_t PeripheralControllerTest::DEVICE_GENERATION = 2; const int32_t PeripheralControllerTest::DEVICE_CONTROLLER_NUMBER = 0; -const Flags PeripheralControllerTest::DEVICE_CLASSES = - Flags(0); // not needed for current tests +const ftl::Flags PeripheralControllerTest::DEVICE_CLASSES = + ftl::Flags(0); // not needed for current tests const int32_t PeripheralControllerTest::EVENTHUB_ID = 1; // --- BatteryControllerTest --- diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h index cb00e719f8..29d33662ab 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h @@ -16,20 +16,20 @@ #pragma once +#include + +#include +#include #include +#include +#include + #include #include #include #include -#include - -#include #include "DisplayHardware/Hal.h" -#include "math/HashCombine.h" - -#include -#include namespace std { template @@ -84,13 +84,13 @@ class StateInterface { public: virtual ~StateInterface() = default; - virtual Flags update(const compositionengine::OutputLayer* layer) = 0; + virtual ftl::Flags update(const compositionengine::OutputLayer* layer) = 0; virtual size_t getHash() const = 0; virtual LayerStateField getField() const = 0; - virtual Flags getFieldIfDifferent(const StateInterface* other) const = 0; + virtual ftl::Flags getFieldIfDifferent(const StateInterface* other) const = 0; virtual bool equals(const StateInterface* other) const = 0; @@ -152,12 +152,12 @@ public: ~OutputLayerState() override = default; // Returns this member's field flag if it was changed - Flags update(const compositionengine::OutputLayer* layer) override { + ftl::Flags update(const compositionengine::OutputLayer* layer) override { T newValue = mReader(layer); return update(newValue); } - Flags update(const T& newValue) { + ftl::Flags update(const T& newValue) { if (!mEquals(mValue, newValue)) { mValue = newValue; mHash = {}; @@ -176,14 +176,14 @@ public: return *mHash; } - Flags getFieldIfDifferent(const StateInterface* other) const override { + ftl::Flags getFieldIfDifferent(const StateInterface* other) const override { if (other->getField() != FIELD) { return {}; } // The early return ensures that this downcast is sound const OutputLayerState* otherState = static_cast(other); - return *this != *otherState ? FIELD : Flags{}; + return *this != *otherState ? FIELD : ftl::Flags{}; } bool equals(const StateInterface* other) const override { @@ -215,7 +215,7 @@ public: LayerState(compositionengine::OutputLayer* layer); // Returns which fields were updated - Flags update(compositionengine::OutputLayer*); + ftl::Flags update(compositionengine::OutputLayer*); // Computes a hash for this LayerState. // The hash is only computed from NonUniqueFields, and excludes GraphicBuffers since they are @@ -224,7 +224,7 @@ public: // Returns the bit-set of differing fields between this LayerState and another LayerState. // This bit-set is based on NonUniqueFields only, and excludes GraphicBuffers. - Flags getDifferingFields(const LayerState& other) const; + ftl::Flags getDifferingFields(const LayerState& other) const; compositionengine::OutputLayer* getOutputLayer() const { return mOutputLayer; } int32_t getId() const { return mId.get(); } diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h index ef1560e23d..6be673597e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h @@ -16,6 +16,8 @@ #pragma once +#include + #include namespace android::compositionengine::impl::planner { @@ -35,7 +37,7 @@ public: // This implies that only one layer is allowed to differ in an approximate match. size_t differingIndex; // Set of fields that differ for the differing layer in the approximate match. - Flags differingFields; + ftl::Flags differingFields; }; // Returns an approximate match when comparing this layer stack with the provided list of diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp index c79ca0d959..f439caf9e1 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp @@ -41,7 +41,7 @@ LayerState::LayerState(compositionengine::OutputLayer* layer) update(layer); } -Flags LayerState::update(compositionengine::OutputLayer* layer) { +ftl::Flags LayerState::update(compositionengine::OutputLayer* layer) { ALOGE_IF(mOutputLayer != layer && layer->getLayerFE().getSequence() != mId.get(), "[%s] Expected mOutputLayer ID to never change: %d, %d", __func__, layer->getLayerFE().getSequence(), mId.get()); @@ -50,7 +50,7 @@ Flags LayerState::update(compositionengine::OutputLayer* layer) // same, i.e., the LayerFE is the same. An example use-case is screen rotation. mOutputLayer = layer; - Flags differences; + ftl::Flags differences; // Update the unique fields as well, since we have to set them at least // once from the OutputLayer @@ -76,8 +76,8 @@ size_t LayerState::getHash() const { return hash; } -Flags LayerState::getDifferingFields(const LayerState& other) const { - Flags differences; +ftl::Flags LayerState::getDifferingFields(const LayerState& other) const { + ftl::Flags differences; auto myFields = getNonUniqueFields(); auto otherFields = other.getNonUniqueFields(); for (size_t i = 0; i < myFields.size(); ++i) { diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp index 74d27015d7..c8413eb8bc 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp @@ -97,7 +97,7 @@ void Planner::plan( if (const auto layerEntry = mPreviousLayers.find(id); layerEntry != mPreviousLayers.end()) { // Track changes from previous info LayerState& state = layerEntry->second; - Flags differences = state.update(layer); + ftl::Flags differences = state.update(layer); if (differences.get() == 0) { state.incrementFramesSinceBufferUpdate(); } else { diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp index 2d53583ed8..2fc029fdc6 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp @@ -57,7 +57,7 @@ std::optional LayerStack::getApproximateMatch( return std::nullopt; } - Flags differingFields = mLayers[i].getDifferingFields(*other[i]); + ftl::Flags differingFields = mLayers[i].getDifferingFields(*other[i]); // If we don't find an approximate match on this layer, then the LayerStacks differ // by too much, so return nothing diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp index bd4ff13236..5c6e8da58c 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp @@ -97,12 +97,12 @@ struct LayerStateTest : public testing::Test { void verifyUniqueDifferingFields(const LayerState& lhs, const LayerState& rhs) { EXPECT_EQ(lhs.getHash(), rhs.getHash()); - EXPECT_EQ(Flags(LayerStateField::None), lhs.getDifferingFields(rhs)); - EXPECT_EQ(Flags(LayerStateField::None), rhs.getDifferingFields(lhs)); + EXPECT_EQ(ftl::Flags(LayerStateField::None), lhs.getDifferingFields(rhs)); + EXPECT_EQ(ftl::Flags(LayerStateField::None), rhs.getDifferingFields(lhs)); } void verifyNonUniqueDifferingFields(const LayerState& lhs, const LayerState& rhs, - Flags fields) { + ftl::Flags fields) { EXPECT_NE(lhs.getHash(), rhs.getHash()); EXPECT_EQ(fields, lhs.getDifferingFields(rhs)); @@ -159,9 +159,9 @@ TEST_F(LayerStateTest, updateId) { sp newLayerFE = sp::make(); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionState, sSequenceIdTwo); - Flags updates = mLayerState->update(&newOutputLayer); + ftl::Flags updates = mLayerState->update(&newOutputLayer); EXPECT_EQ(sSequenceIdTwo, mLayerState->getId()); - EXPECT_EQ(Flags(LayerStateField::Id), updates); + EXPECT_EQ(ftl::Flags(LayerStateField::Id), updates); } TEST_F(LayerStateTest, compareId) { @@ -204,9 +204,9 @@ TEST_F(LayerStateTest, updateName) { sp newLayerFE = sp::make(); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionState, sSequenceId, sDebugNameTwo); - Flags updates = mLayerState->update(&newOutputLayer); + ftl::Flags updates = mLayerState->update(&newOutputLayer); EXPECT_EQ(sDebugNameTwo, mLayerState->getName()); - EXPECT_EQ(Flags(LayerStateField::Name), updates); + EXPECT_EQ(ftl::Flags(LayerStateField::Name), updates); } TEST_F(LayerStateTest, compareName) { @@ -253,9 +253,9 @@ TEST_F(LayerStateTest, updateDisplayFrame) { outputLayerCompositionStateTwo.displayFrame = sRectTwo; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo, layerFECompositionState); - Flags updates = mLayerState->update(&newOutputLayer); + ftl::Flags updates = mLayerState->update(&newOutputLayer); EXPECT_EQ(sRectTwo, mLayerState->getDisplayFrame()); - EXPECT_EQ(Flags(LayerStateField::DisplayFrame), updates); + EXPECT_EQ(ftl::Flags(LayerStateField::DisplayFrame), updates); } TEST_F(LayerStateTest, compareDisplayFrame) { @@ -315,9 +315,9 @@ TEST_F(LayerStateTest, updateCompositionType) { layerFECompositionStateTwo.compositionType = Composition::SOLID_COLOR; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); + ftl::Flags updates = mLayerState->update(&newOutputLayer); EXPECT_EQ(Composition::SOLID_COLOR, mLayerState->getCompositionType()); - EXPECT_EQ(Flags(LayerStateField::CompositionType), updates); + EXPECT_EQ(ftl::Flags(LayerStateField::CompositionType), updates); } TEST_F(LayerStateTest, compareCompositionType) { @@ -357,8 +357,8 @@ TEST_F(LayerStateTest, updateBuffer) { layerFECompositionStateTwo.buffer = new GraphicBuffer(); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::Buffer), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::Buffer), updates); } TEST_F(LayerStateTest, updateBufferSingleBufferedLegacy) { @@ -380,8 +380,8 @@ TEST_F(LayerStateTest, updateBufferSingleBufferedLegacy) { layerFECompositionStateTwo.frameNumber = i; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::Buffer), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::Buffer), updates); } } @@ -404,8 +404,8 @@ TEST_F(LayerStateTest, updateBufferSingleBufferedUsage) { for (uint64_t i = 0; i < 10; i++) { setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::Buffer), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::Buffer), updates); } } @@ -446,8 +446,8 @@ TEST_F(LayerStateTest, updateSourceCrop) { outputLayerCompositionStateTwo.sourceCrop = sFloatRectTwo; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo, layerFECompositionState); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::SourceCrop), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::SourceCrop), updates); } TEST_F(LayerStateTest, compareSourceCrop) { @@ -485,8 +485,8 @@ TEST_F(LayerStateTest, updateBufferTransform) { outputLayerCompositionStateTwo.bufferTransform = Hwc2::Transform::FLIP_V; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo, layerFECompositionState); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::BufferTransform), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::BufferTransform), updates); } TEST_F(LayerStateTest, compareBufferTransform) { @@ -525,8 +525,8 @@ TEST_F(LayerStateTest, updateBlendMode) { layerFECompositionStateTwo.blendMode = hal::BlendMode::PREMULTIPLIED; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::BlendMode), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::BlendMode), updates); } TEST_F(LayerStateTest, compareBlendMode) { @@ -564,8 +564,8 @@ TEST_F(LayerStateTest, updateAlpha) { layerFECompositionStateTwo.alpha = sAlphaTwo; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::Alpha), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::Alpha), updates); } TEST_F(LayerStateTest, compareAlpha) { @@ -603,8 +603,8 @@ TEST_F(LayerStateTest, updateLayerMetadata) { layerFECompositionStateTwo.metadata[sMetadataKeyTwo] = sMetadataValueTwo; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::LayerMetadata), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::LayerMetadata), updates); } TEST_F(LayerStateTest, compareLayerMetadata) { @@ -652,8 +652,8 @@ TEST_F(LayerStateTest, updateVisibleRegion) { outputLayerCompositionStateTwo.visibleRegion = sRegionTwo; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo, layerFECompositionState); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::VisibleRegion), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::VisibleRegion), updates); } TEST_F(LayerStateTest, compareVisibleRegion) { @@ -691,8 +691,8 @@ TEST_F(LayerStateTest, updateDataspace) { outputLayerCompositionStateTwo.dataspace = ui::Dataspace::DISPLAY_P3; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo, layerFECompositionState); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::Dataspace), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::Dataspace), updates); } TEST_F(LayerStateTest, compareDataspace) { @@ -738,9 +738,9 @@ TEST_F(LayerStateTest, updatePixelFormat) { "buffer2"); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::Buffer) | - Flags(LayerStateField::PixelFormat), + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::Buffer) | + ftl::Flags(LayerStateField::PixelFormat), updates); } @@ -768,7 +768,7 @@ TEST_F(LayerStateTest, comparePixelFormat) { auto otherLayerState = std::make_unique(&newOutputLayer); verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, - Flags(LayerStateField::PixelFormat)); + ftl::Flags(LayerStateField::PixelFormat)); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); @@ -790,8 +790,8 @@ TEST_F(LayerStateTest, updateColorTransform) { layerFECompositionStateTwo.colorTransform = sMat4One; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::ColorTransform), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::ColorTransform), updates); } TEST_F(LayerStateTest, compareColorTransform) { @@ -831,8 +831,8 @@ TEST_F(LayerStateTest, updateSidebandStream) { layerFECompositionStateTwo.sidebandStream = NativeHandle::create(sFakeSidebandStreamTwo, false); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::SidebandStream), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::SidebandStream), updates); } TEST_F(LayerStateTest, compareSidebandStream) { @@ -870,8 +870,8 @@ TEST_F(LayerStateTest, updateSolidColor) { layerFECompositionStateTwo.color = sHalf4Two; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::SolidColor), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::SolidColor), updates); } TEST_F(LayerStateTest, compareSolidColor) { @@ -909,8 +909,8 @@ TEST_F(LayerStateTest, updateBackgroundBlur) { layerFECompositionStateTwo.backgroundBlurRadius = sBgBlurRadiusTwo; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::BackgroundBlurRadius), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::BackgroundBlurRadius), updates); } TEST_F(LayerStateTest, compareBackgroundBlur) { @@ -949,8 +949,8 @@ TEST_F(LayerStateTest, updateBlurRegions) { layerFECompositionStateTwo.blurRegions.push_back(sBlurRegionTwo); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::BlurRegions), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::BlurRegions), updates); } TEST_F(LayerStateTest, compareBlurRegions) { diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index b4fb51f9d5..3803a78670 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -19,20 +19,20 @@ #pragma clang diagnostic ignored "-Wconversion" // #define LOG_NDEBUG 0 -#include "VirtualDisplaySurface.h" #include -#include "HWComposer.h" -#include "SurfaceFlinger.h" - -#include #include +#include #include #include #include #include +#include "HWComposer.h" +#include "SurfaceFlinger.h" +#include "VirtualDisplaySurface.h" + #define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \ mDisplayName.c_str(), ##__VA_ARGS__) #define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \ @@ -657,7 +657,7 @@ auto VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) -> std::string VirtualDisplaySurface::toString(CompositionType type) { using namespace std::literals; - return type == CompositionType::Unknown ? "Unknown"s : Flags(type).string(); + return type == CompositionType::Unknown ? "Unknown"s : ftl::Flags(type).string(); } } // namespace android diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 894fb8d47b..41e048715c 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -82,11 +82,13 @@ namespace { constexpr int kDumpTableRowLength = 159; } // namespace +using namespace ftl::flag_operators; + using base::StringAppendF; -using namespace android::flag_operators; -using PresentState = frametimeline::SurfaceFrame::PresentState; using gui::WindowInfo; +using PresentState = frametimeline::SurfaceFrame::PresentState; + std::atomic Layer::sSequence{1}; Layer::Layer(const LayerCreationArgs& args) diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Features.h b/services/surfaceflinger/Scheduler/include/scheduler/Features.h index 0e96678420..b3a6a606c3 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/Features.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/Features.h @@ -16,10 +16,10 @@ #pragma once -#include - #include +#include + namespace android::scheduler { enum class Feature : std::uint8_t { @@ -29,6 +29,6 @@ enum class Feature : std::uint8_t { kTracePredictedVsync = 0b1000, }; -using FeatureFlags = Flags; +using FeatureFlags = ftl::Flags; } // namespace android::scheduler diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index d249b60f2a..a73eccf0e5 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -429,7 +429,7 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta bufferProto.height(), bufferProto.pixel_format(), bufferProto.usage())); layer.bufferData->frameNumber = bufferProto.frame_number(); - layer.bufferData->flags = Flags(bufferProto.flags()); + layer.bufferData->flags = ftl::Flags(bufferProto.flags()); layer.bufferData->cachedBuffer.id = bufferProto.cached_buffer_id(); layer.bufferData->acquireFence = Fence::NO_FENCE; } diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 14d8f987b0..fa36d9c16b 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -34,12 +34,13 @@ using namespace std::chrono_literals; using namespace std::placeholders; -using namespace android::flag_operators; using testing::_; using testing::Invoke; namespace android { +using namespace ftl::flag_operators; + namespace { constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = PhysicalDisplayId::fromPort(111u); -- cgit v1.2.3-59-g8ed1b From c3f39b1a6b3882767fd633b09e2002ce5091d8da Mon Sep 17 00:00:00 2001 From: chaviw Date: Fri, 10 Sep 2021 13:41:39 -0500 Subject: Add isClone to WindowInfo Add a flag about whether the window is a clone to help identity the original windows vs clones Test: WindowInfo_test Bug: 230300971 Change-Id: Idb890482a86243790407abe83732e3ca7c7cfdba --- libs/gui/WindowInfo.cpp | 8 +++++--- libs/gui/include/gui/WindowInfo.h | 2 ++ libs/gui/tests/WindowInfo_test.cpp | 2 ++ services/surfaceflinger/Layer.cpp | 1 + 4 files changed, 10 insertions(+), 3 deletions(-) (limited to 'libs/gui/WindowInfo.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 804ce4fac0..4e966d1393 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -76,7 +76,7 @@ bool WindowInfo::operator==(const WindowInfo& info) const { info.inputConfig == inputConfig && info.displayId == displayId && info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType && - info.layoutParamsFlags == layoutParamsFlags; + info.layoutParamsFlags == layoutParamsFlags && info.isClone == isClone; } status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { @@ -124,7 +124,8 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->write(touchableRegion) ?: parcel->writeBool(replaceTouchableRegionWithCrop) ?: parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?: - parcel->writeStrongBinder(windowToken); + parcel->writeStrongBinder(windowToken) ?: + parcel->writeBool(isClone); // clang-format on return status; } @@ -175,7 +176,8 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->read(touchableRegion) ?: parcel->readBool(&replaceTouchableRegionWithCrop) ?: parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?: - parcel->readNullableStrongBinder(&windowToken); + parcel->readNullableStrongBinder(&windowToken) ?: + parcel->readBool(&isClone); // clang-format on if (status != OK) { diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 0e1d25812e..169f7f022b 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -236,6 +236,8 @@ struct WindowInfo : public Parcelable { void setInputConfig(ftl::Flags config, bool value); + bool isClone = false; + void addTouchableRegion(const Rect& region); bool touchableRegionContainsPoint(int32_t x, int32_t y) const; diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index c51b244c50..99658ccd4b 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -71,6 +71,7 @@ TEST(WindowInfo, Parcelling) { i.applicationInfo.name = "ApplicationFooBar"; i.applicationInfo.token = new BBinder(); i.applicationInfo.dispatchingTimeoutMillis = 0x12345678ABCD; + i.isClone = true; Parcel p; i.writeToParcel(&p); @@ -101,6 +102,7 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop); ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle); ASSERT_EQ(i.applicationInfo, i2.applicationInfo); + ASSERT_EQ(i.isClone, i2.isClone); } TEST(InputApplicationInfo, Parcelling) { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index e1eec8b97e..a1e2c0d39a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2430,6 +2430,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp // If the layer is a clone, we need to crop the input region to cloned root to prevent // touches from going outside the cloned area. if (isClone()) { + info.isClone = true; if (const sp clonedRoot = getClonedRoot()) { const Rect rect = displayTransform.transform(Rect{clonedRoot->mScreenBounds}); info.touchableRegion = info.touchableRegion.intersect(rect); -- cgit v1.2.3-59-g8ed1b