diff options
Diffstat (limited to 'libs')
52 files changed, 1118 insertions, 244 deletions
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 97626bec7d..2524c5f6d2 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -14,7 +14,9 @@ cc_test { address: true, }, srcs: [ + "Flags_test.cpp", "future_test.cpp", + "NamedEnum_test.cpp", "small_map_test.cpp", "small_vector_test.cpp", "static_vector_test.cpp", @@ -25,4 +27,12 @@ cc_test { "-Wextra", "-Wpedantic", ], + + header_libs: [ + "libbase_headers", + ], + + shared_libs: [ + "libbase", + ], } diff --git a/libs/input/tests/Flags_test.cpp b/libs/ftl/Flags_test.cpp index 6de030f7cf..8c00b5299b 100644 --- a/libs/input/tests/Flags_test.cpp +++ b/libs/ftl/Flags_test.cpp @@ -15,7 +15,7 @@ */ #include <gtest/gtest.h> -#include <input/Flags.h> +#include <ftl/Flags.h> #include <type_traits> diff --git a/libs/input/tests/NamedEnum_test.cpp b/libs/ftl/NamedEnum_test.cpp index 74a0044387..dff2b8aaa1 100644 --- a/libs/input/tests/NamedEnum_test.cpp +++ b/libs/ftl/NamedEnum_test.cpp @@ -15,7 +15,7 @@ */ #include <gtest/gtest.h> -#include <input/NamedEnum.h> +#include <ftl/NamedEnum.h> namespace android { diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 64203f78a8..326da3a7b5 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -51,6 +51,59 @@ cc_library_headers { ], } +// AIDL files that should be exposed to java +filegroup { + name: "guiconstants_aidl", + srcs: [ + "android/**/TouchOcclusionMode.aidl", + ], +} + +cc_library_static { + name: "libgui_window_info_static", + vendor_available: true, + host_supported: true, + srcs: [ + ":guiconstants_aidl", + "android/gui/FocusRequest.aidl", + "android/gui/InputApplicationInfo.aidl", + "android/gui/IWindowInfosListener.aidl", + "android/gui/IWindowInfosReportedListener.aidl", + "android/gui/WindowInfo.aidl", + "WindowInfo.cpp", + ], + + shared_libs: [ + "libbinder", + ], + + local_include_dirs: [ + "include", + ], + + export_shared_lib_headers: [ + "libbinder", + ], + + static_libs: [ + "libui-types", + ], + + aidl: { + export_aidl_headers: true + }, + + include_dirs: [ + "frameworks/native/include", + ], + + target: { + darwin: { + enabled: false, + }, + }, +} + filegroup { name: "libgui_aidl", srcs: ["aidl/**/*.aidl"], @@ -77,12 +130,15 @@ cc_library_static { "libbinder", ], + static_libs: [ + "libui-types", + ], + aidl: { export_aidl_headers: true } } - cc_library_shared { name: "libgui", vendor_available: true, @@ -96,9 +152,11 @@ cc_library_shared { static_libs: [ "libgui_aidl_static", + "libgui_window_info_static", ], export_static_lib_headers: [ "libgui_aidl_static", + "libgui_window_info_static", ], srcs: [ @@ -139,6 +197,7 @@ cc_library_shared { "SyncFeatures.cpp", "TransactionTracing.cpp", "view/Surface.cpp", + "WindowInfosListenerReporter.cpp", "bufferqueue/1.0/B2HProducerListener.cpp", "bufferqueue/1.0/H2BGraphicBufferProducer.cpp", "bufferqueue/2.0/B2HProducerListener.cpp", @@ -150,13 +209,11 @@ cc_library_shared { "libbinder", "libbufferhub", "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui. - "libinput", "libpdx_default_transport", ], export_shared_lib_headers: [ "libbinder", - "libinput", ], export_header_lib_headers: [ @@ -168,7 +225,6 @@ cc_library_shared { vendor: { cflags: [ "-DNO_BUFFERHUB", - "-DNO_INPUT", ], exclude_srcs: [ "BufferHubConsumer.cpp", @@ -178,7 +234,6 @@ cc_library_shared { "android.frameworks.bufferhub@1.0", "libbufferhub", "libbufferhubqueue", - "libinput", "libpdx_default_transport", ], }, diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 56a9683773..70f2ae770b 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -38,7 +38,7 @@ using namespace std::chrono_literals; namespace { -inline const char* toString(bool b) { +inline const char* boolToString(bool b) { return b ? "true" : "false"; } } // namespace @@ -530,7 +530,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 " applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d" " graphicBufferId=%" PRIu64 "%s transform=%d", - mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction), + mSize.width, mSize.height, bufferItem.mFrameNumber, boolToString(applyTransaction), bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "", static_cast<uint32_t>(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(), bufferItem.mAutoRefresh ? " mAutoRefresh" : "", bufferItem.mTransform); @@ -560,7 +560,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { mNumFrameAvailable + mNumAcquired - mPendingRelease.size()); BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber, - toString(nextTransactionSet)); + boolToString(nextTransactionSet)); processNextBufferLocked(nextTransactionSet /* useNextTransaction */); } diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 5023b6bb81..2930154ad4 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -34,7 +34,6 @@ #include <gui/BufferQueueCore.h> #include <gui/IConsumerListener.h> #include <gui/IProducerListener.h> -#include <gui/ISurfaceComposer.h> #include <private/gui/ComposerService.h> #include <system/window.h> diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 0d7795e1ba..2a980bd118 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -44,6 +44,7 @@ namespace android { +using gui::IWindowInfosListener; using ui::ColorMode; class BpSurfaceComposer : public BpInterface<ISurfaceComposer> @@ -1227,6 +1228,22 @@ public: return reply.readInt32(buffers); } + + status_t addWindowInfosListener( + const sp<IWindowInfosListener>& windowInfosListener) const override { + Parcel data, reply; + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener)); + return remote()->transact(BnSurfaceComposer::ADD_WINDOW_INFOS_LISTENER, data, &reply); + } + + status_t removeWindowInfosListener( + const sp<IWindowInfosListener>& windowInfosListener) const override { + Parcel data, reply; + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener)); + return remote()->transact(BnSurfaceComposer::REMOVE_WINDOW_INFOS_LISTENER, data, &reply); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -2107,6 +2124,20 @@ status_t BnSurfaceComposer::onTransact( SAFE_PARCEL(reply->writeBool, success); return err; } + case ADD_WINDOW_INFOS_LISTENER: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IWindowInfosListener> listener; + SAFE_PARCEL(data.readStrongBinder, &listener); + + return addWindowInfosListener(listener); + } + case REMOVE_WINDOW_INFOS_LISTENER: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IWindowInfosListener> listener; + SAFE_PARCEL(data.readStrongBinder, &listener); + + return removeWindowInfosListener(listener); + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 076c90dd23..5bed69cfc7 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -31,6 +31,9 @@ namespace android { +using gui::FocusRequest; +using gui::WindowInfoHandle; + layer_state_t::layer_state_t() : what(0), x(0), @@ -95,9 +98,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeFloat, color.r); SAFE_PARCEL(output.writeFloat, color.g); SAFE_PARCEL(output.writeFloat, color.b); -#ifndef NO_INPUT - SAFE_PARCEL(inputHandle->writeToParcel, &output); -#endif + SAFE_PARCEL(windowInfoHandle->writeToParcel, &output); SAFE_PARCEL(output.write, transparentRegion); SAFE_PARCEL(output.writeUint32, transform); SAFE_PARCEL(output.writeBool, transformToDisplayInverse); @@ -173,6 +174,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.write, destinationFrame); SAFE_PARCEL(output.writeBool, isTrustedOverlay); + SAFE_PARCEL(output.writeStrongBinder, releaseBufferEndpoint); return NO_ERROR; } @@ -207,9 +209,7 @@ status_t layer_state_t::read(const Parcel& input) color.g = tmpFloat; SAFE_PARCEL(input.readFloat, &tmpFloat); color.b = tmpFloat; -#ifndef NO_INPUT - SAFE_PARCEL(inputHandle->readFromParcel, &input); -#endif + SAFE_PARCEL(windowInfoHandle->readFromParcel, &input); SAFE_PARCEL(input.read, transparentRegion); SAFE_PARCEL(input.readUint32, &transform); @@ -304,6 +304,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.read, destinationFrame); SAFE_PARCEL(input.readBool, &isTrustedOverlay); + SAFE_PARCEL(input.readNullableStrongBinder, &releaseBufferEndpoint); return NO_ERROR; } @@ -318,6 +319,7 @@ status_t ComposerState::read(const Parcel& input) { DisplayState::DisplayState() : what(0), layerStack(0), + flags(0), layerStackSpaceRect(Rect::EMPTY_RECT), orientedDisplaySpaceRect(Rect::EMPTY_RECT), width(0), @@ -328,6 +330,7 @@ status_t DisplayState::write(Parcel& output) const { SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(surface)); SAFE_PARCEL(output.writeUint32, what); SAFE_PARCEL(output.writeUint32, layerStack); + SAFE_PARCEL(output.writeUint32, flags); SAFE_PARCEL(output.writeUint32, toRotationInt(orientation)); SAFE_PARCEL(output.write, layerStackSpaceRect); SAFE_PARCEL(output.write, orientedDisplaySpaceRect); @@ -344,6 +347,7 @@ status_t DisplayState::read(const Parcel& input) { SAFE_PARCEL(input.readUint32, &what); SAFE_PARCEL(input.readUint32, &layerStack); + SAFE_PARCEL(input.readUint32, &flags); uint32_t tmpUint = 0; SAFE_PARCEL(input.readUint32, &tmpUint); orientation = ui::toRotation(tmpUint); @@ -364,6 +368,10 @@ void DisplayState::merge(const DisplayState& other) { what |= eLayerStackChanged; layerStack = other.layerStack; } + if (other.what & eFlagsChanged) { + what |= eFlagsChanged; + flags = other.flags; + } if (other.what & eDisplayProjectionChanged) { what |= eDisplayProjectionChanged; orientation = other.orientation; @@ -487,14 +495,10 @@ void layer_state_t::merge(const layer_state_t& other) { if (other.what & eHasListenerCallbacksChanged) { what |= eHasListenerCallbacksChanged; } - -#ifndef NO_INPUT if (other.what & eInputInfoChanged) { what |= eInputInfoChanged; - inputHandle = new InputWindowHandle(*other.inputHandle); + windowInfoHandle = new WindowInfoHandle(*other.windowInfoHandle); } -#endif - if (other.what & eCachedBufferChanged) { what |= eCachedBufferChanged; cachedBuffer = other.cachedBuffer; @@ -593,11 +597,9 @@ status_t layer_state_t::matrix22_t::read(const Parcel& input) { bool InputWindowCommands::merge(const InputWindowCommands& other) { bool changes = false; -#ifndef NO_INPUT changes |= !other.focusRequests.empty(); focusRequests.insert(focusRequests.end(), std::make_move_iterator(other.focusRequests.begin()), std::make_move_iterator(other.focusRequests.end())); -#endif changes |= other.syncInputWindows && !syncInputWindows; syncInputWindows |= other.syncInputWindows; return changes; @@ -605,31 +607,23 @@ bool InputWindowCommands::merge(const InputWindowCommands& other) { bool InputWindowCommands::empty() const { bool empty = true; -#ifndef NO_INPUT empty = focusRequests.empty() && !syncInputWindows; -#endif return empty; } void InputWindowCommands::clear() { -#ifndef NO_INPUT focusRequests.clear(); -#endif syncInputWindows = false; } status_t InputWindowCommands::write(Parcel& output) const { -#ifndef NO_INPUT SAFE_PARCEL(output.writeParcelableVector, focusRequests); -#endif SAFE_PARCEL(output.writeBool, syncInputWindows); return NO_ERROR; } status_t InputWindowCommands::read(const Parcel& input) { -#ifndef NO_INPUT SAFE_PARCEL(input.readParcelableVector, &focusRequests); -#endif SAFE_PARCEL(input.readBool, &syncInputWindows); return NO_ERROR; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 96da8efd19..dc71b6a212 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -19,6 +19,7 @@ #include <stdint.h> #include <sys/types.h> +#include <android/gui/IWindowInfosListener.h> #include <utils/Errors.h> #include <utils/Log.h> #include <utils/SortedVector.h> @@ -39,14 +40,11 @@ #include <gui/LayerState.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> +#include <gui/WindowInfo.h> #include <private/gui/ParcelUtils.h> #include <ui/DisplayMode.h> #include <ui/DynamicDisplayInfo.h> -#ifndef NO_INPUT -#include <input/InputWindow.h> -#endif - #include <private/gui/ComposerService.h> // This server size should always be smaller than the server cache size @@ -54,6 +52,10 @@ namespace android { +using gui::FocusRequest; +using gui::WindowInfo; +using gui::WindowInfoHandle; +using gui::WindowInfosListener; using ui::ColorMode; // --------------------------------------------------------------------------- @@ -95,6 +97,7 @@ bool ComposerService::connectLocked() { if (instance.mComposerService == nullptr) { if (ComposerService::getInstance().connectLocked()) { ALOGD("ComposerService reconnected"); + WindowInfosListenerReporter::getInstance()->reconnect(instance.mComposerService); } } return instance.mComposerService; @@ -144,8 +147,16 @@ int64_t TransactionCompletedListener::getNextIdLocked() { return mCallbackIdCounter++; } +sp<TransactionCompletedListener> TransactionCompletedListener::sInstance = nullptr; + +void TransactionCompletedListener::setInstance(const sp<TransactionCompletedListener>& listener) { + sInstance = listener; +} + sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() { - static sp<TransactionCompletedListener> sInstance = new TransactionCompletedListener; + if (sInstance == nullptr) { + sInstance = new TransactionCompletedListener; + } return sInstance; } @@ -1271,6 +1282,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe removeReleaseBufferCallback(s); s->what |= layer_state_t::eBufferChanged; s->buffer = buffer; + s->releaseBufferEndpoint = IInterface::asBinder(TransactionCompletedListener::getIInstance()); if (mIsAutoTimestamp) { mDesiredPresentTime = systemTime(); } @@ -1491,16 +1503,14 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame return *this; } -#ifndef NO_INPUT SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo( - const sp<SurfaceControl>& sc, - const InputWindowInfo& info) { + const sp<SurfaceControl>& sc, const WindowInfo& info) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } - s->inputHandle = new InputWindowHandle(info); + s->windowInfoHandle = new WindowInfoHandle(info); s->what |= layer_state_t::eInputInfoChanged; return *this; } @@ -1516,8 +1526,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInpu return *this; } -#endif - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorTransform( const sp<SurfaceControl>& sc, const mat3& matrix, const vec3& translation) { layer_state_t* s = getLayerState(sc); @@ -1758,6 +1766,12 @@ void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp<IBinder>& s.what |= DisplayState::eLayerStackChanged; } +void SurfaceComposerClient::Transaction::setDisplayFlags(const sp<IBinder>& token, uint32_t flags) { + DisplayState& s(getDisplayState(token)); + s.flags = flags; + s.what |= DisplayState::eFlagsChanged; +} + void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation, const Rect& layerStackRect, @@ -1779,15 +1793,10 @@ void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token // --------------------------------------------------------------------------- -SurfaceComposerClient::SurfaceComposerClient() - : mStatus(NO_INIT) -{ -} +SurfaceComposerClient::SurfaceComposerClient() : mStatus(NO_INIT) {} SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& client) - : mStatus(NO_ERROR), mClient(client) -{ -} + : mStatus(NO_ERROR), mClient(client) {} void SurfaceComposerClient::onFirstRef() { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); @@ -2153,6 +2162,18 @@ int SurfaceComposerClient::getGPUContextPriority() { return ComposerService::getComposerService()->getGPUContextPriority(); } +status_t SurfaceComposerClient::addWindowInfosListener( + const sp<WindowInfosListener>& windowInfosListener) { + return WindowInfosListenerReporter::getInstance() + ->addWindowInfosListener(windowInfosListener, ComposerService::getComposerService()); +} + +status_t SurfaceComposerClient::removeWindowInfosListener( + const sp<WindowInfosListener>& windowInfosListener) { + return WindowInfosListenerReporter::getInstance() + ->removeWindowInfosListener(windowInfosListener, ComposerService::getComposerService()); +} + // ---------------------------------------------------------------------------- status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs, diff --git a/libs/input/InputWindow.cpp b/libs/gui/WindowInfo.cpp index 99477200db..ff0bb8aa55 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/gui/WindowInfo.cpp @@ -15,43 +15,40 @@ */ #include <type_traits> -#define LOG_TAG "InputWindow" +#define LOG_TAG "WindowInfo" #define LOG_NDEBUG 0 #include <android-base/stringprintf.h> #include <binder/Parcel.h> -#include <input/InputTransport.h> -#include <input/InputWindow.h> +#include <gui/WindowInfo.h> #include <log/log.h> -namespace android { +namespace android::gui { - -// --- InputWindowInfo --- -void InputWindowInfo::addTouchableRegion(const Rect& region) { +// --- WindowInfo --- +void WindowInfo::addTouchableRegion(const Rect& region) { touchableRegion.orSelf(region); } -bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { - return touchableRegion.contains(x,y); +bool WindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { + return touchableRegion.contains(x, y); } -bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { - return x >= frameLeft && x < frameRight - && y >= frameTop && y < frameBottom; +bool WindowInfo::frameContainsPoint(int32_t x, int32_t y) const { + return x >= frameLeft && x < frameRight && y >= frameTop && y < frameBottom; } -bool InputWindowInfo::supportsSplitTouch() const { +bool WindowInfo::supportsSplitTouch() const { return flags.test(Flag::SPLIT_TOUCH); } -bool InputWindowInfo::overlaps(const InputWindowInfo* other) const { - return frameLeft < other->frameRight && frameRight > other->frameLeft - && frameTop < other->frameBottom && frameBottom > other->frameTop; +bool WindowInfo::overlaps(const WindowInfo* other) const { + return frameLeft < other->frameRight && frameRight > other->frameLeft && + frameTop < other->frameBottom && frameBottom > other->frameTop; } -bool InputWindowInfo::operator==(const InputWindowInfo& info) 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 && @@ -69,7 +66,7 @@ bool InputWindowInfo::operator==(const InputWindowInfo& info) const { info.applicationInfo == applicationInfo; } -status_t InputWindowInfo::writeToParcel(android::Parcel* parcel) const { +status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { if (parcel == nullptr) { ALOGE("%s: Null parcel", __func__); return BAD_VALUE; @@ -86,7 +83,7 @@ status_t InputWindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeInt32(id) ?: parcel->writeUtf8AsUtf16(name) ?: parcel->writeInt32(flags.get()) ?: - parcel->writeInt32(static_cast<std::underlying_type_t<InputWindowInfo::Type>>(type)) ?: + parcel->writeInt32(static_cast<std::underlying_type_t<WindowInfo::Type>>(type)) ?: parcel->writeInt32(frameLeft) ?: parcel->writeInt32(frameTop) ?: parcel->writeInt32(frameRight) ?: @@ -122,7 +119,7 @@ status_t InputWindowInfo::writeToParcel(android::Parcel* parcel) const { return status; } -status_t InputWindowInfo::readFromParcel(const android::Parcel* parcel) { +status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { if (parcel == nullptr) { ALOGE("%s: Null parcel", __func__); return BAD_VALUE; @@ -176,11 +173,13 @@ status_t InputWindowInfo::readFromParcel(const android::Parcel* parcel) { touchOcclusionMode = static_cast<TouchOcclusionMode>(touchOcclusionModeInt); inputFeatures = Flags<Feature>(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; @@ -192,33 +191,33 @@ status_t InputWindowInfo::readFromParcel(const android::Parcel* parcel) { return OK; } -// --- InputWindowHandle --- +// --- WindowInfoHandle --- -InputWindowHandle::InputWindowHandle() {} +WindowInfoHandle::WindowInfoHandle() {} -InputWindowHandle::~InputWindowHandle() {} +WindowInfoHandle::~WindowInfoHandle() {} -InputWindowHandle::InputWindowHandle(const InputWindowHandle& other) : mInfo(other.mInfo) {} +WindowInfoHandle::WindowInfoHandle(const WindowInfoHandle& other) : mInfo(other.mInfo) {} -InputWindowHandle::InputWindowHandle(const InputWindowInfo& other) : mInfo(other) {} +WindowInfoHandle::WindowInfoHandle(const WindowInfo& other) : mInfo(other) {} -status_t InputWindowHandle::writeToParcel(android::Parcel* parcel) const { +status_t WindowInfoHandle::writeToParcel(android::Parcel* parcel) const { return mInfo.writeToParcel(parcel); } -status_t InputWindowHandle::readFromParcel(const android::Parcel* parcel) { +status_t WindowInfoHandle::readFromParcel(const android::Parcel* parcel) { return mInfo.readFromParcel(parcel); } -void InputWindowHandle::releaseChannel() { +void WindowInfoHandle::releaseChannel() { mInfo.token.clear(); } -sp<IBinder> InputWindowHandle::getToken() const { +sp<IBinder> WindowInfoHandle::getToken() const { return mInfo.token; } -void InputWindowHandle::updateFrom(sp<InputWindowHandle> handle) { +void WindowInfoHandle::updateFrom(sp<WindowInfoHandle> handle) { mInfo = handle->mInfo; } -} // namespace android +} // namespace android::gui diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp new file mode 100644 index 0000000000..c00a4389ad --- /dev/null +++ b/libs/gui/WindowInfosListenerReporter.cpp @@ -0,0 +1,98 @@ +/* + * 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 <gui/ISurfaceComposer.h> +#include <gui/WindowInfosListenerReporter.h> + +namespace android { + +using gui::IWindowInfosReportedListener; +using gui::WindowInfo; +using gui::WindowInfosListener; + +sp<WindowInfosListenerReporter> WindowInfosListenerReporter::getInstance() { + static sp<WindowInfosListenerReporter> sInstance = new WindowInfosListenerReporter; + return sInstance; +} + +status_t WindowInfosListenerReporter::addWindowInfosListener( + const sp<WindowInfosListener>& windowInfosListener, + const sp<ISurfaceComposer>& surfaceComposer) { + status_t status = OK; + { + std::scoped_lock lock(mListenersMutex); + if (mWindowInfosListeners.empty()) { + status = surfaceComposer->addWindowInfosListener(this); + } + + if (status == OK) { + mWindowInfosListeners.insert(windowInfosListener); + } + } + + return status; +} + +status_t WindowInfosListenerReporter::removeWindowInfosListener( + const sp<WindowInfosListener>& windowInfosListener, + const sp<ISurfaceComposer>& surfaceComposer) { + status_t status = OK; + { + std::scoped_lock lock(mListenersMutex); + if (mWindowInfosListeners.size() == 1) { + status = surfaceComposer->removeWindowInfosListener(this); + } + + if (status == OK) { + mWindowInfosListeners.erase(windowInfosListener); + } + } + + return status; +} + +binder::Status WindowInfosListenerReporter::onWindowInfosChanged( + const std::vector<WindowInfo>& windowInfos, + const sp<IWindowInfosReportedListener>& windowInfosReportedListener) { + std::unordered_set<sp<WindowInfosListener>, ISurfaceComposer::SpHash<WindowInfosListener>> + windowInfosListeners; + + { + std::scoped_lock lock(mListenersMutex); + for (auto listener : mWindowInfosListeners) { + windowInfosListeners.insert(listener); + } + } + + for (auto listener : windowInfosListeners) { + listener->onWindowInfosChanged(windowInfos); + } + + if (windowInfosReportedListener) { + windowInfosReportedListener->onWindowInfosReported(); + } + + return binder::Status::ok(); +} + +void WindowInfosListenerReporter::reconnect(const sp<ISurfaceComposer>& composerService) { + std::scoped_lock lock(mListenersMutex); + if (!mWindowInfosListeners.empty()) { + composerService->addWindowInfosListener(this); + } +} + +} // namespace android
\ No newline at end of file diff --git a/libs/input/android/FocusRequest.aidl b/libs/gui/android/gui/FocusRequest.aidl index 8812d34a72..90186351c5 100644 --- a/libs/input/android/FocusRequest.aidl +++ b/libs/gui/android/gui/FocusRequest.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android; +package android.gui; /** @hide */ parcelable FocusRequest { diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl new file mode 100644 index 0000000000..d4553ca82d --- /dev/null +++ b/libs/gui/android/gui/IWindowInfosListener.aidl @@ -0,0 +1,26 @@ +/* + * 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; + +import android.gui.IWindowInfosReportedListener; +import android.gui.WindowInfo; + +/** @hide */ +oneway interface IWindowInfosListener +{ + void onWindowInfosChanged(in WindowInfo[] windowInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener); +} diff --git a/libs/input/android/os/ISetInputWindowsListener.aidl b/libs/gui/android/gui/IWindowInfosReportedListener.aidl index bb58fb671b..0e4cce61a2 100644 --- a/libs/input/android/os/ISetInputWindowsListener.aidl +++ b/libs/gui/android/gui/IWindowInfosReportedListener.aidl @@ -14,10 +14,10 @@ * limitations under the License. */ -package android.os; +package android.gui; /** @hide */ -oneway interface ISetInputWindowsListener +oneway interface IWindowInfosReportedListener { - void onSetInputWindowsFinished(); + void onWindowInfosReported(); } diff --git a/libs/input/android/InputApplicationInfo.aidl b/libs/gui/android/gui/InputApplicationInfo.aidl index 933603916d..c0fd666543 100644 --- a/libs/input/android/InputApplicationInfo.aidl +++ b/libs/gui/android/gui/InputApplicationInfo.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android; +package android.gui; parcelable InputApplicationInfo { @nullable IBinder token; diff --git a/libs/input/android/os/TouchOcclusionMode.aidl b/libs/gui/android/gui/TouchOcclusionMode.aidl index 106f159a50..d91d052135 100644 --- a/libs/input/android/os/TouchOcclusionMode.aidl +++ b/libs/gui/android/gui/TouchOcclusionMode.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.os; +package android.gui; /** diff --git a/libs/input/android/InputWindowInfo.aidl b/libs/gui/android/gui/WindowInfo.aidl index eeaf400227..2c85d155a8 100644 --- a/libs/input/android/InputWindowInfo.aidl +++ b/libs/gui/android/gui/WindowInfo.aidl @@ -1,5 +1,4 @@ -/* //device/java/android/android/view/InputChannel.aidl -** +/* ** Copyright 2020, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,6 +14,6 @@ ** limitations under the License. */ -package android; +package android.gui; -parcelable InputWindowInfo cpp_header "input/InputWindow.h"; +parcelable WindowInfo cpp_header "gui/WindowInfo.h"; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 2a3f6a43d9..ad7bcb7d12 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -22,11 +22,12 @@ #include <android/gui/IScreenCaptureListener.h> #include <android/gui/ITransactionTraceListener.h> #include <android/gui/ITunnelModeEnabledListener.h> +#include <android/gui/IWindowInfosListener.h> #include <binder/IBinder.h> #include <binder/IInterface.h> +#include <ftl/Flags.h> #include <gui/FrameTimelineInfo.h> #include <gui/ITransactionCompletedListener.h> -#include <input/Flags.h> #include <math/vec4.h> #include <stdint.h> #include <sys/types.h> @@ -552,6 +553,11 @@ public: * in MIN_UNDEQUEUED_BUFFERS. */ virtual status_t getMaxAcquiredBufferCount(int* buffers) const = 0; + + virtual status_t addWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0; + virtual status_t removeWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0; }; // ---------------------------------------------------------------------------- @@ -624,6 +630,8 @@ public: ON_PULL_ATOM, ADD_TUNNEL_MODE_ENABLED_LISTENER, REMOVE_TUNNEL_MODE_ENABLED_LISTENER, + ADD_WINDOW_INFOS_LISTENER, + REMOVE_WINDOW_INFOS_LISTENER, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/InputApplication.h b/libs/gui/include/gui/InputApplication.h new file mode 100644 index 0000000000..679c2a1754 --- /dev/null +++ b/libs/gui/include/gui/InputApplication.h @@ -0,0 +1,79 @@ +/* + * 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. + */ + +#ifndef _UI_INPUT_APPLICATION_H +#define _UI_INPUT_APPLICATION_H + +#include <string> + +#include <android/gui/InputApplicationInfo.h> + +#include <binder/IBinder.h> +#include <binder/Parcel.h> +#include <binder/Parcelable.h> + +#include <utils/RefBase.h> +#include <utils/Timers.h> + +namespace android { + +/* + * Handle for an application that can receive input. + * + * Used by the native input dispatcher as a handle for the window manager objects + * that describe an application. + */ +class InputApplicationHandle { +public: + inline const gui::InputApplicationInfo* getInfo() const { return &mInfo; } + + inline std::string getName() const { return !mInfo.name.empty() ? mInfo.name : "<invalid>"; } + + inline std::chrono::nanoseconds getDispatchingTimeout( + std::chrono::nanoseconds defaultValue) const { + return mInfo.token ? std::chrono::milliseconds(mInfo.dispatchingTimeoutMillis) + : defaultValue; + } + + inline sp<IBinder> getApplicationToken() const { return mInfo.token; } + + bool operator==(const InputApplicationHandle& other) const { + return getName() == other.getName() && getApplicationToken() == other.getApplicationToken(); + } + + bool operator!=(const InputApplicationHandle& other) const { return !(*this == other); } + + /** + * Requests that the state of this object be updated to reflect + * the most current available information about the application. + * + * This method should only be called from within the input dispatcher's + * critical section. + * + * Returns true on success, or false if the handle is no longer valid. + */ + virtual bool updateInfo() = 0; + +protected: + InputApplicationHandle() = default; + virtual ~InputApplicationHandle() = default; + + gui::InputApplicationInfo mInfo; +}; + +} // namespace android + +#endif // _UI_INPUT_APPLICATION_H diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 3e57ff611e..8dc8b9a87b 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -26,14 +26,12 @@ #include <gui/ITransactionCompletedListener.h> #include <math/mat4.h> -#ifndef NO_INPUT -#include <android/FocusRequest.h> -#include <input/InputWindow.h> -#endif +#include <android/gui/FocusRequest.h> #include <gui/ISurfaceComposer.h> #include <gui/LayerMetadata.h> #include <gui/SurfaceControl.h> +#include <gui/WindowInfo.h> #include <math/vec3.h> #include <ui/BlurRegion.h> #include <ui/GraphicTypes.h> @@ -178,9 +176,7 @@ struct layer_state_t { mat4 colorTransform; std::vector<BlurRegion> blurRegions; -#ifndef NO_INPUT - sp<InputWindowHandle> inputHandle = new InputWindowHandle(); -#endif + sp<gui::WindowInfoHandle> windowInfoHandle = new gui::WindowInfoHandle(); client_cache_t cachedBuffer; @@ -246,6 +242,11 @@ struct layer_state_t { // is used to remove the old callback from the client process map if it is // overwritten by another setBuffer call. ReleaseCallbackId releaseCallbackId; + + // Stores which endpoint the release information should be sent to. We don't want to send the + // releaseCallbackId and release fence to all listeners so we store which listener the setBuffer + // was called with. + sp<IBinder> releaseBufferEndpoint; }; struct ComposerState { @@ -259,7 +260,8 @@ struct DisplayState { eSurfaceChanged = 0x01, eLayerStackChanged = 0x02, eDisplayProjectionChanged = 0x04, - eDisplaySizeChanged = 0x08 + eDisplaySizeChanged = 0x08, + eFlagsChanged = 0x10 }; DisplayState(); @@ -269,6 +271,7 @@ struct DisplayState { sp<IBinder> token; sp<IGraphicBufferProducer> surface; uint32_t layerStack; + uint32_t flags; // These states define how layers are projected onto the physical display. // @@ -292,9 +295,7 @@ struct DisplayState { }; struct InputWindowCommands { -#ifndef NO_INPUT - std::vector<FocusRequest> focusRequests; -#endif + std::vector<gui::FocusRequest> focusRequests; bool syncInputWindows{false}; // Merges the passed in commands and returns true if there were any changes. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index baa0567617..1d758e0dde 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -42,6 +42,7 @@ #include <gui/ITransactionCompletedListener.h> #include <gui/LayerState.h> #include <gui/SurfaceControl.h> +#include <gui/WindowInfosListenerReporter.h> #include <math/vec3.h> namespace android { @@ -502,11 +503,9 @@ public: // Set the framenumber generated by the graphics producer to mimic BufferQueue behaviour. Transaction& setFrameNumber(const sp<SurfaceControl>& sc, uint64_t frameNumber); -#ifndef NO_INPUT - Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info); - Transaction& setFocusedWindow(const FocusRequest& request); + Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const gui::WindowInfo& info); + Transaction& setFocusedWindow(const gui::FocusRequest& request); Transaction& syncInputWindows(); -#endif // Set a color transform matrix on the given layer on the built-in display. Transaction& setColorTransform(const sp<SurfaceControl>& sc, const mat3& matrix, @@ -569,6 +568,8 @@ public: void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack); + void setDisplayFlags(const sp<IBinder>& token, uint32_t flags); + /* setDisplayProjection() defines the projection of layer stacks * to a given display. * @@ -622,6 +623,9 @@ public: static status_t removeTunnelModeEnabledListener( const sp<gui::ITunnelModeEnabledListener>& listener); + status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener); + status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener); + private: virtual void onFirstRef(); @@ -651,8 +655,10 @@ public: }; class TransactionCompletedListener : public BnTransactionCompletedListener { +public: TransactionCompletedListener(); +protected: int64_t getNextIdLocked() REQUIRES(mMutex); std::mutex mMutex; @@ -730,8 +736,12 @@ public: void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence, uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) override; + // For Testing Only + static void setInstance(const sp<TransactionCompletedListener>&); + private: ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&); + static sp<TransactionCompletedListener> sInstance; }; } // namespace android diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h new file mode 100644 index 0000000000..7af1f0e95a --- /dev/null +++ b/libs/gui/include/gui/WindowInfo.h @@ -0,0 +1,264 @@ +/* + * 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. + */ + +#pragma once + +#include <android/gui/TouchOcclusionMode.h> +#include <binder/Parcel.h> +#include <binder/Parcelable.h> +#include <ftl/Flags.h> +#include <gui/constants.h> +#include <ui/Rect.h> +#include <ui/Region.h> +#include <ui/Transform.h> +#include <utils/RefBase.h> +#include <utils/Timers.h> + +#include "InputApplication.h" + +namespace android::gui { + +/* + * Describes the properties of a window that can receive input. + */ +struct WindowInfo : public Parcelable { + WindowInfo() = default; + + // Window flags from WindowManager.LayoutParams + enum class Flag : uint32_t { + ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, + DIM_BEHIND = 0x00000002, + BLUR_BEHIND = 0x00000004, + NOT_FOCUSABLE = 0x00000008, + NOT_TOUCHABLE = 0x00000010, + NOT_TOUCH_MODAL = 0x00000020, + TOUCHABLE_WHEN_WAKING = 0x00000040, + KEEP_SCREEN_ON = 0x00000080, + LAYOUT_IN_SCREEN = 0x00000100, + LAYOUT_NO_LIMITS = 0x00000200, + FULLSCREEN = 0x00000400, + FORCE_NOT_FULLSCREEN = 0x00000800, + DITHER = 0x00001000, + SECURE = 0x00002000, + SCALED = 0x00004000, + IGNORE_CHEEK_PRESSES = 0x00008000, + LAYOUT_INSET_DECOR = 0x00010000, + ALT_FOCUSABLE_IM = 0x00020000, + WATCH_OUTSIDE_TOUCH = 0x00040000, + SHOW_WHEN_LOCKED = 0x00080000, + SHOW_WALLPAPER = 0x00100000, + TURN_SCREEN_ON = 0x00200000, + DISMISS_KEYGUARD = 0x00400000, + SPLIT_TOUCH = 0x00800000, + HARDWARE_ACCELERATED = 0x01000000, + LAYOUT_IN_OVERSCAN = 0x02000000, + TRANSLUCENT_STATUS = 0x04000000, + TRANSLUCENT_NAVIGATION = 0x08000000, + LOCAL_FOCUS_MODE = 0x10000000, + SLIPPERY = 0x20000000, + LAYOUT_ATTACHED_IN_DECOR = 0x40000000, + DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000, + }; // Window types from WindowManager.LayoutParams + + enum class Type : int32_t { + UNKNOWN = 0, + FIRST_APPLICATION_WINDOW = 1, + BASE_APPLICATION = 1, + APPLICATION = 2, + APPLICATION_STARTING = 3, + LAST_APPLICATION_WINDOW = 99, + FIRST_SUB_WINDOW = 1000, + APPLICATION_PANEL = FIRST_SUB_WINDOW, + APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1, + APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2, + APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3, + APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4, + LAST_SUB_WINDOW = 1999, + FIRST_SYSTEM_WINDOW = 2000, + STATUS_BAR = FIRST_SYSTEM_WINDOW, + SEARCH_BAR = FIRST_SYSTEM_WINDOW + 1, + PHONE = FIRST_SYSTEM_WINDOW + 2, + SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3, + KEYGUARD = FIRST_SYSTEM_WINDOW + 4, + TOAST = FIRST_SYSTEM_WINDOW + 5, + SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6, + PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7, + SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW + 8, + KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW + 9, + SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10, + INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11, + INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW + 12, + WALLPAPER = FIRST_SYSTEM_WINDOW + 13, + STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW + 14, + SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 15, + DRAG = FIRST_SYSTEM_WINDOW + 16, + STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW + 17, + POINTER = FIRST_SYSTEM_WINDOW + 18, + NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19, + VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW + 20, + BOOT_PROGRESS = FIRST_SYSTEM_WINDOW + 21, + INPUT_CONSUMER = FIRST_SYSTEM_WINDOW + 22, + NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW + 24, + MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27, + ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32, + DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34, + ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39, + NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40, + LAST_SYSTEM_WINDOW = 2999, + }; + + enum class Feature { + DISABLE_TOUCH_PAD_GESTURES = 0x00000001, + NO_INPUT_CHANNEL = 0x00000002, + DISABLE_USER_ACTIVITY = 0x00000004, + }; + + /* These values are filled in by the WM and passed through SurfaceFlinger + * unless specified otherwise. + */ + // This value should NOT be used to uniquely identify the window. There may be different + // input windows that have the same token. + sp<IBinder> token; + // This uniquely identifies the input window. + int32_t id = -1; + std::string name; + Flags<Flag> flags; + Type type = Type::UNKNOWN; + std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5); + + /* These values are filled in by SurfaceFlinger. */ + int32_t frameLeft = -1; + int32_t frameTop = -1; + int32_t frameRight = -1; + int32_t frameBottom = -1; + + /* + * SurfaceFlinger consumes this value to shrink the computed frame. This is + * different from shrinking the touchable region in that it DOES shift the coordinate + * space where-as the touchable region does not and is more like "cropping". This + * is used for window shadows. + */ + int32_t surfaceInset = 0; + + // A global scaling factor for all windows. Unlike windowScaleX/Y this results + // in scaling of the TOUCH_MAJOR/TOUCH_MINOR axis. + float globalScaleFactor = 1.0f; + + // The opacity of this window, from 0.0 to 1.0 (inclusive). + // An alpha of 1.0 means fully opaque and 0.0 means fully transparent. + float alpha; + + // Transform applied to individual windows. + ui::Transform transform; + + // Display orientation. 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. + */ + 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<Feature> inputFeatures; + int32_t displayId = ADISPLAY_ID_NONE; + int32_t portalToDisplayId = ADISPLAY_ID_NONE; + InputApplicationInfo applicationInfo; + bool replaceTouchableRegionWithCrop = false; + wp<IBinder> touchableRegionCropHandle; + + void addTouchableRegion(const Rect& region); + + bool touchableRegionContainsPoint(int32_t x, int32_t y) const; + + bool frameContainsPoint(int32_t x, int32_t y) const; + + bool supportsSplitTouch() const; + + bool overlaps(const WindowInfo* other) const; + + bool operator==(const WindowInfo& inputChannel) const; + + status_t writeToParcel(android::Parcel* parcel) const override; + + status_t readFromParcel(const android::Parcel* parcel) override; +}; + +/* + * Handle for a window that can receive input. + * + * Used by the native input dispatcher to indirectly refer to the window manager objects + * that describe a window. + */ +class WindowInfoHandle : public RefBase { +public: + explicit WindowInfoHandle(); + WindowInfoHandle(const WindowInfoHandle& other); + WindowInfoHandle(const WindowInfo& other); + + inline const WindowInfo* getInfo() const { return &mInfo; } + + sp<IBinder> getToken() const; + + int32_t getId() const { return mInfo.id; } + + sp<IBinder> getApplicationToken() { return mInfo.applicationInfo.token; } + + inline std::string getName() const { return !mInfo.name.empty() ? mInfo.name : "<invalid>"; } + + inline std::chrono::nanoseconds getDispatchingTimeout( + std::chrono::nanoseconds defaultValue) const { + return mInfo.token ? std::chrono::nanoseconds(mInfo.dispatchingTimeout) : defaultValue; + } + + /** + * Updates from another input window handle. + */ + void updateFrom(const sp<WindowInfoHandle> handle); + + /** + * Releases the channel used by the associated information when it is + * no longer needed. + */ + void releaseChannel(); + + // Not override since this class is not derrived from Parcelable. + status_t readFromParcel(const android::Parcel* parcel); + status_t writeToParcel(android::Parcel* parcel) const; + +protected: + virtual ~WindowInfoHandle(); + + WindowInfo mInfo; +}; +} // namespace android::gui
\ No newline at end of file diff --git a/libs/gui/include/gui/WindowInfosListener.h b/libs/gui/include/gui/WindowInfosListener.h new file mode 100644 index 0000000000..8a70b9bb57 --- /dev/null +++ b/libs/gui/include/gui/WindowInfosListener.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 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 <gui/WindowInfo.h> +#include <utils/RefBase.h> + +namespace android::gui { + +class WindowInfosListener : public virtual RefBase { +public: + virtual void onWindowInfosChanged(const std::vector<WindowInfo>& /*windowInfos*/) = 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 new file mode 100644 index 0000000000..7cb96e0a30 --- /dev/null +++ b/libs/gui/include/gui/WindowInfosListenerReporter.h @@ -0,0 +1,48 @@ +/* + * 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 <android/gui/BnWindowInfosListener.h> +#include <android/gui/IWindowInfosReportedListener.h> +#include <binder/IBinder.h> +#include <gui/ISurfaceComposer.h> +#include <gui/WindowInfosListener.h> +#include <utils/Mutex.h> +#include <unordered_set> + +namespace android { +class ISurfaceComposer; + +class WindowInfosListenerReporter : public gui::BnWindowInfosListener { +public: + static sp<WindowInfosListenerReporter> getInstance(); + binder::Status onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos, + const sp<gui::IWindowInfosReportedListener>&) override; + + status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener, + const sp<ISurfaceComposer>&); + status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener, + const sp<ISurfaceComposer>&); + void reconnect(const sp<ISurfaceComposer>&); + +private: + std::mutex mListenersMutex; + std::unordered_set<sp<gui::WindowInfosListener>, + ISurfaceComposer::SpHash<gui::WindowInfosListener>> + mWindowInfosListeners GUARDED_BY(mListenersMutex); +}; +} // namespace android
\ No newline at end of file diff --git a/libs/gui/include/gui/constants.h b/libs/gui/include/gui/constants.h new file mode 100644 index 0000000000..8eab3783e9 --- /dev/null +++ b/libs/gui/include/gui/constants.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 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 <stdint.h> + +namespace android { + +/** + * Invalid value for display size. Used when display size isn't available. + */ +constexpr int32_t INVALID_DISPLAY_SIZE = 0; + +enum { + /* Used when an event is not associated with any display. + * Typically used for non-pointer events. */ + ADISPLAY_ID_NONE = -1, + + /* The default display id. */ + ADISPLAY_ID_DEFAULT = 0, +}; + +} // namespace android
\ No newline at end of file diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index c801c6243a..3d26c3d858 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -43,6 +43,7 @@ cc_test { "SurfaceTextureMultiContextGL_test.cpp", "Surface_test.cpp", "TextureRenderer.cpp", + "WindowInfo_test.cpp", ], shared_libs: [ diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 49c44a78d1..fc84c1b619 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -37,9 +37,9 @@ #include <gui/SurfaceControl.h> #include <android/os/IInputFlinger.h> +#include <gui/WindowInfo.h> #include <input/Input.h> #include <input/InputTransport.h> -#include <input/InputWindow.h> #include <ui/DisplayMode.h> #include <ui/Rect.h> @@ -49,6 +49,11 @@ using android::os::IInputFlinger; using android::hardware::graphics::common::V1_1::BufferUsage; +using android::gui::FocusRequest; +using android::gui::InputApplicationInfo; +using android::gui::TouchOcclusionMode; +using android::gui::WindowInfo; + namespace android::test { using Transaction = SurfaceComposerClient::Transaction; @@ -221,8 +226,8 @@ private: void populateInputInfo(int width, int height) { mInputInfo.token = mClientChannel->getConnectionToken(); mInputInfo.name = "Test info"; - mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL; - mInputInfo.type = InputWindowInfo::Type::BASE_APPLICATION; + mInputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL; + mInputInfo.type = WindowInfo::Type::BASE_APPLICATION; mInputInfo.dispatchingTimeout = 5s; mInputInfo.globalScaleFactor = 1.0; mInputInfo.focusable = true; @@ -249,7 +254,7 @@ public: std::shared_ptr<InputChannel> mClientChannel; sp<IInputFlinger> mInputFlinger; - InputWindowInfo mInputInfo; + WindowInfo mInputInfo; PreallocatedInputEventFactory mInputEventFactory; InputConsumer* mInputConsumer; @@ -686,7 +691,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<InputSurface> nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; + nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; 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. @@ -706,8 +711,8 @@ TEST_F(InputSurfacesTest, touch_flag_partially_obscured_with_crop) { // AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100); std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; - parentSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; + nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; nonTouchableSurface->mInputInfo.ownerUid = 22222; parentSurface->mInputInfo.ownerUid = 22222; nonTouchableSurface->showAt(0, 0); @@ -730,8 +735,8 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_crop) { // the touchable window. Window behind gets touch with no obscured flags. std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100); std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; - parentSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; + nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; nonTouchableSurface->mInputInfo.ownerUid = 22222; parentSurface->mInputInfo.ownerUid = 22222; nonTouchableSurface->showAt(0, 0); @@ -751,7 +756,7 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_bql) { std::unique_ptr<InputSurface> bufferSurface = InputSurface::makeBufferInputSurface(mComposerClient, 0, 0); - bufferSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; + bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; bufferSurface->mInputInfo.ownerUid = 22222; surface->showAt(10, 10); @@ -766,7 +771,7 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) { std::unique_ptr<BlastInputSurface> bufferSurface = BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0); - bufferSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; + bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; bufferSurface->mInputInfo.ownerUid = 22222; surface->showAt(10, 10); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 59b0c04bc3..a02970c9bc 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -904,6 +904,16 @@ public: status_t getMaxAcquiredBufferCount(int* /*buffers*/) const override { return NO_ERROR; } + status_t addWindowInfosListener( + const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override { + return NO_ERROR; + } + + status_t removeWindowInfosListener( + const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override { + return NO_ERROR; + } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index 493f2f4495..58f3981db2 100644 --- a/libs/input/tests/InputWindow_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -19,16 +19,20 @@ #include <binder/Binder.h> #include <binder/Parcel.h> -#include <input/InputWindow.h> -#include <input/InputTransport.h> +#include <gui/WindowInfo.h> using std::chrono_literals::operator""s; namespace android { + +using gui::InputApplicationInfo; +using gui::TouchOcclusionMode; +using gui::WindowInfo; + namespace test { -TEST(InputWindowInfo, ParcellingWithoutToken) { - InputWindowInfo i, i2; +TEST(WindowInfo, ParcellingWithoutToken) { + WindowInfo i, i2; i.token = nullptr; Parcel p; @@ -38,14 +42,14 @@ TEST(InputWindowInfo, ParcellingWithoutToken) { ASSERT_TRUE(i2.token == nullptr); } -TEST(InputWindowInfo, Parcelling) { +TEST(WindowInfo, Parcelling) { sp<IBinder> touchableRegionCropHandle = new BBinder(); - InputWindowInfo i; + WindowInfo i; i.token = new BBinder(); i.id = 1; i.name = "Foobar"; - i.flags = InputWindowInfo::Flag::SLIPPERY; - i.type = InputWindowInfo::Type::INPUT_METHOD; + i.flags = WindowInfo::Flag::SLIPPERY; + i.type = WindowInfo::Type::INPUT_METHOD; i.dispatchingTimeout = 12s; i.frameLeft = 93; i.frameTop = 34; @@ -55,6 +59,7 @@ TEST(InputWindowInfo, 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; @@ -65,7 +70,7 @@ TEST(InputWindowInfo, Parcelling) { i.ownerPid = 19; i.ownerUid = 24; i.packageName = "com.example.package"; - i.inputFeatures = InputWindowInfo::Feature::DISABLE_USER_ACTIVITY; + i.inputFeatures = WindowInfo::Feature::DISABLE_USER_ACTIVITY; i.displayId = 34; i.portalToDisplayId = 2; i.replaceTouchableRegionWithCrop = true; @@ -77,7 +82,7 @@ TEST(InputWindowInfo, Parcelling) { Parcel p; i.writeToParcel(&p); p.setDataPosition(0); - InputWindowInfo i2; + WindowInfo i2; i2.readFromParcel(&p); ASSERT_EQ(i.token, i2.token); ASSERT_EQ(i.id, i2.id); diff --git a/libs/input/Android.bp b/libs/input/Android.bp index a63ec8fb2a..e73c3b8518 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -30,7 +30,6 @@ filegroup { "android/os/IInputConstants.aidl", "android/os/InputEventInjectionResult.aidl", "android/os/InputEventInjectionSync.aidl", - "android/os/TouchOcclusionMode.aidl", ], } @@ -79,16 +78,11 @@ cc_library { android: { srcs: [ "InputTransport.cpp", - "InputWindow.cpp", - "android/FocusRequest.aidl", - "android/InputApplicationInfo.aidl", "android/os/BlockUntrustedTouchesMode.aidl", "android/os/IInputConstants.aidl", "android/os/IInputFlinger.aidl", "android/os/InputEventInjectionResult.aidl", "android/os/InputEventInjectionSync.aidl", - "android/os/ISetInputWindowsListener.aidl", - "android/os/TouchOcclusionMode.aidl", ], export_shared_lib_headers: ["libbinder"], @@ -99,6 +93,14 @@ cc_library { "libui", ], + static_libs: [ + "libgui_window_info_static", + ], + + export_static_lib_headers: [ + "libgui_window_info_static", + ], + sanitize: { misc_undefined: ["integer"], }, @@ -114,26 +116,29 @@ cc_library { linux_glibc: { srcs: [ "InputTransport.cpp", - "InputWindow.cpp", - "android/FocusRequest.aidl", - "android/InputApplicationInfo.aidl", "android/os/IInputConstants.aidl", "android/os/IInputFlinger.aidl", - "android/os/ISetInputWindowsListener.aidl", - "android/os/TouchOcclusionMode.aidl", ], static_libs: [ "libhostgraphics", + "libgui_window_info_static", ], shared_libs: [ "libbinder", ], + + export_static_lib_headers: [ + "libgui_window_info_static", + ], }, }, aidl: { local_include_dirs: ["."], export_aidl_headers: true, + include_dirs: [ + "frameworks/native/libs/gui", + ], }, } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index d954d23507..35209f7a07 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -25,6 +25,7 @@ #include <android-base/properties.h> #include <android-base/stringprintf.h> +#include <gui/constants.h> #include <input/Input.h> #include <input/InputDevice.h> #include <input/InputEventLabels.h> @@ -75,14 +76,11 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { return result; } -// Rotates the given point to the transform's orientation. If the display width and height are +// Rotates the given point to the specified orientation. If the display width and height are // provided, the point is rotated in the screen space. Otherwise, the point is rotated about the // origin. This helper is used to avoid the extra overhead of creating new Transforms. -vec2 rotatePoint(const ui::Transform& transform, float x, float y, int32_t displayWidth = 0, +vec2 rotatePoint(uint32_t orientation, float x, float y, int32_t displayWidth = 0, int32_t displayHeight = 0) { - // 0x7 encapsulates all 3 rotations (see ui::Transform::RotationFlags) - static const int ALL_ROTATIONS_MASK = 0x7; - const uint32_t orientation = (transform.getOrientation() & ALL_ROTATIONS_MASK); if (orientation == ui::Transform::ROT_0) { return {x, y}; } @@ -101,6 +99,19 @@ vec2 rotatePoint(const ui::Transform& transform, float x, float y, int32_t displ return xy; } +vec2 applyTransformWithoutTranslation(const ui::Transform& transform, float x, float y) { + const vec2 transformedXy = transform.transform(x, y); + const vec2 transformedOrigin = transform.transform(0, 0); + return transformedXy - transformedOrigin; +} + +bool shouldDisregardWindowTranslation(uint32_t source) { + // Pointer events are the only type of events that refer to absolute coordinates on the display, + // so we should apply the entire window transform. For other types of events, we should make + // sure to not apply the window translation/offset. + return (source & AINPUT_SOURCE_CLASS_POINTER) == 0; +} + } // namespace const char* motionClassificationToString(MotionClassification classification) { @@ -315,6 +326,8 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, globalScaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, globalScaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, globalScaleFactor); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_X, windowXScale); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale); } void PointerCoords::scale(float globalScaleFactor) { @@ -383,6 +396,15 @@ void PointerCoords::transform(const ui::Transform& transform) { setAxisValue(AMOTION_EVENT_AXIS_X, xy.x); setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y); + if (BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_RELATIVE_X) || + BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_RELATIVE_Y)) { + const ui::Transform rotation(transform.getOrientation()); + const vec2 relativeXy = rotation.transform(getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), + getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); + setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, relativeXy.x); + setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, relativeXy.y); + } + if (BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_ORIENTATION)) { const float val = getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(transform, val)); @@ -410,9 +432,9 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int3 int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, float yPrecision, float rawXCursorPosition, float rawYCursorPosition, - int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, - nsecs_t eventTime, size_t pointerCount, - const PointerProperties* pointerProperties, + uint32_t displayOrientation, int32_t displayWidth, + int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, + size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { InputEvent::initialize(id, deviceId, source, displayId, hmac); mAction = action; @@ -427,6 +449,7 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int3 mYPrecision = yPrecision; mRawXCursorPosition = rawXCursorPosition; mRawYCursorPosition = rawYCursorPosition; + mDisplayOrientation = displayOrientation; mDisplayWidth = displayWidth; mDisplayHeight = displayHeight; mDownTime = downTime; @@ -452,6 +475,7 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mYPrecision = other->mYPrecision; mRawXCursorPosition = other->mRawXCursorPosition; mRawYCursorPosition = other->mRawYCursorPosition; + mDisplayOrientation = other->mDisplayOrientation; mDisplayWidth = other->mDisplayWidth; mDisplayHeight = other->mDisplayHeight; mDownTime = other->mDownTime; @@ -521,25 +545,48 @@ float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { // For compatibility, convert raw coordinates into "oriented screen space". Once app // developers are educated about getRaw, we can consider removing this. - const vec2 xy = rotatePoint(mTransform, coords->getX(), coords->getY(), mDisplayWidth, - mDisplayHeight); + const vec2 xy = shouldDisregardWindowTranslation(mSource) + ? rotatePoint(mDisplayOrientation, coords->getX(), coords->getY()) + : rotatePoint(mDisplayOrientation, coords->getX(), coords->getY(), mDisplayWidth, + mDisplayHeight); static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); return xy[axis]; } + if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { + // For compatibility, since we convert raw coordinates into "oriented screen space", we + // need to convert the relative axes into the same orientation for consistency. + const vec2 relativeXy = rotatePoint(mDisplayOrientation, + coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), + coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); + return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; + } + return coords->getAxisValue(axis); } float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, - size_t historicalIndex) const { + size_t historicalIndex) const { const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex); if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { - const vec2 xy = mTransform.transform(coords->getXYValue()); + const vec2 xy = shouldDisregardWindowTranslation(mSource) + ? applyTransformWithoutTranslation(mTransform, coords->getX(), coords->getY()) + : mTransform.transform(coords->getXYValue()); static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); return xy[axis]; } + if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) { + const vec2 relativeXy = + applyTransformWithoutTranslation(mTransform, + coords->getAxisValue( + AMOTION_EVENT_AXIS_RELATIVE_X), + coords->getAxisValue( + AMOTION_EVENT_AXIS_RELATIVE_Y)); + return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y; + } + return coords->getAxisValue(axis); } @@ -595,6 +642,13 @@ void MotionEvent::applyTransform(const std::array<float, 9>& matrix) { // Apply the transformation to all samples. std::for_each(mSamplePointerCoords.begin(), mSamplePointerCoords.end(), [&transform](PointerCoords& c) { c.transform(transform); }); + + if (mRawXCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION && + mRawYCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION) { + const vec2 cursor = transform.transform(mRawXCursorPosition, mRawYCursorPosition); + mRawXCursorPosition = cursor.x; + mRawYCursorPosition = cursor.y; + } } #ifdef __linux__ @@ -655,6 +709,7 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mYPrecision = parcel->readFloat(); mRawXCursorPosition = parcel->readFloat(); mRawYCursorPosition = parcel->readFloat(); + mDisplayOrientation = parcel->readUint32(); mDisplayWidth = parcel->readInt32(); mDisplayHeight = parcel->readInt32(); mDownTime = parcel->readInt64(); @@ -716,6 +771,7 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeFloat(mYPrecision); parcel->writeFloat(mRawXCursorPosition); parcel->writeFloat(mRawYCursorPosition); + parcel->writeUint32(mDisplayOrientation); parcel->writeInt32(mDisplayWidth); parcel->writeInt32(mDisplayHeight); parcel->writeInt64(mDownTime); diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index 30c42a3daa..220c8e1e6e 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -21,9 +21,9 @@ #include <ctype.h> #include <android-base/stringprintf.h> +#include <ftl/NamedEnum.h> #include <input/InputDevice.h> #include <input/InputEventLabels.h> -#include <input/NamedEnum.h> using android::base::StringPrintf; diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index dd1c46265c..ea8b9a7ec8 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -33,8 +33,8 @@ static constexpr bool DEBUG_TRANSPORT_ACTIONS = false; #include <log/log.h> #include <utils/Trace.h> +#include <ftl/NamedEnum.h> #include <input/InputTransport.h> -#include <input/NamedEnum.h> using android::base::StringPrintf; @@ -242,9 +242,11 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { msg->body.motion.xCursorPosition = body.motion.xCursorPosition; // float yCursorPosition msg->body.motion.yCursorPosition = body.motion.yCursorPosition; - // int32_t displayW + // uint32_t displayOrientation + msg->body.motion.displayOrientation = body.motion.displayOrientation; + // int32_t displayWidth msg->body.motion.displayWidth = body.motion.displayWidth; - // int32_t displayH + // int32_t displayHeight msg->body.motion.displayHeight = body.motion.displayHeight; // uint32_t pointerCount msg->body.motion.pointerCount = body.motion.pointerCount; @@ -533,9 +535,10 @@ status_t InputPublisher::publishMotionEvent( std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, float xPrecision, - float yPrecision, float xCursorPosition, float yCursorPosition, int32_t displayWidth, - int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { + float yPrecision, float xCursorPosition, float yCursorPosition, uint32_t displayOrientation, + int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, + uint32_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords) { if (ATRACE_ENABLED()) { std::string message = StringPrintf( "publishMotionEvent(inputChannel=%s, action=%" PRId32 ")", @@ -593,6 +596,7 @@ status_t InputPublisher::publishMotionEvent( msg.body.motion.yPrecision = yPrecision; msg.body.motion.xCursorPosition = xCursorPosition; msg.body.motion.yCursorPosition = yCursorPosition; + msg.body.motion.displayOrientation = displayOrientation; msg.body.motion.displayWidth = displayWidth; msg.body.motion.displayHeight = displayHeight; msg.body.motion.downTime = downTime; @@ -1361,9 +1365,9 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage msg->body.motion.buttonState, msg->body.motion.classification, transform, msg->body.motion.xPrecision, msg->body.motion.yPrecision, msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition, - msg->body.motion.displayWidth, msg->body.motion.displayHeight, - msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount, - pointerProperties, pointerCoords); + msg->body.motion.displayOrientation, msg->body.motion.displayWidth, + msg->body.motion.displayHeight, msg->body.motion.downTime, + msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords); } void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) { diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index 44f3f34994..3baeb55009 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -28,10 +28,11 @@ #include <input/KeyCharacterMap.h> #include <input/Keyboard.h> -#include <utils/Log.h> +#include <gui/constants.h> #include <utils/Errors.h> -#include <utils/Tokenizer.h> +#include <utils/Log.h> #include <utils/Timers.h> +#include <utils/Tokenizer.h> // Enables debug output for the parser. #define DEBUG_PARSER 0 diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp index fa5a5412e6..c365ab070e 100644 --- a/libs/input/KeyLayoutMap.cpp +++ b/libs/input/KeyLayoutMap.cpp @@ -19,10 +19,10 @@ #include <stdlib.h> #include <android/keycodes.h> +#include <ftl/NamedEnum.h> #include <input/InputEventLabels.h> #include <input/KeyLayoutMap.h> #include <input/Keyboard.h> -#include <input/NamedEnum.h> #include <utils/Errors.h> #include <utils/Log.h> #include <utils/Timers.h> diff --git a/libs/input/android/os/IInputFlinger.aidl b/libs/input/android/os/IInputFlinger.aidl index 1771d192af..00ebd4d34f 100644 --- a/libs/input/android/os/IInputFlinger.aidl +++ b/libs/input/android/os/IInputFlinger.aidl @@ -16,20 +16,13 @@ package android.os; -import android.FocusRequest; import android.InputChannel; -import android.InputWindowInfo; -import android.os.ISetInputWindowsListener; +import android.gui.FocusRequest; +import android.gui.WindowInfo; /** @hide */ interface IInputFlinger { - // SurfaceFlinger is the caller of this method, it uses the listener callback to ensure the - // ordering when needed. - // SurfaceFlinger calls this only every VSync, so overflow of binder's oneway buffer - // shouldn't be a concern. - oneway void setInputWindows(in InputWindowInfo[] inputHandles, - in @nullable ISetInputWindowsListener setInputWindowsListener); InputChannel createInputChannel(in @utf8InCpp String name); void removeInputChannel(in IBinder connectionToken); /** diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index 6ffc6a8926..18ab1cb522 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -11,26 +11,24 @@ package { cc_test { name: "libinput_tests", srcs: [ - "NamedEnum_test.cpp", - "Flags_test.cpp", "IdGenerator_test.cpp", "InputChannel_test.cpp", "InputDevice_test.cpp", "InputEvent_test.cpp", "InputPublisherAndConsumer_test.cpp", - "InputWindow_test.cpp", "TouchVideoFrame_test.cpp", "VelocityTracker_test.cpp", "VerifiedInputEvent_test.cpp", ], + static_libs: [ + "libgui_window_info_static", + "libinput", + ], cflags: [ "-Wall", "-Wextra", "-Werror", ], - static_libs: [ - "libinput", - ], shared_libs: [ "libbase", "libbinder", diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index 3b76ddbb7c..b1ef7534e4 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -21,6 +21,7 @@ #include <attestation/HmacKeyManager.h> #include <binder/Parcel.h> #include <gtest/gtest.h> +#include <gui/constants.h> #include <input/Input.h> namespace android { @@ -293,7 +294,7 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE, mTransform, 2.0f, 2.1f, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, + ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, pointerProperties, pointerCoords); @@ -610,12 +611,12 @@ TEST_F(MotionEventTest, Transform) { } MotionEvent event; ui::Transform identityTransform; - event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, + event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, identityTransform, 0 /*xPrecision*/, 0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/, 2 /*yCursorPosition*/, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, + ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); float originalRawX = 0 + 3; @@ -658,13 +659,17 @@ TEST_F(MotionEventTest, Transform) { ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); } -MotionEvent createTouchDownEvent(int x, int y, ui::Transform transform) { +MotionEvent createTouchDownEvent(float x, float y, float dx, float dy, + const ui::Transform& transform, + uint32_t displayOrientation = ui::Transform::ROT_0) { std::vector<PointerProperties> pointerProperties; pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER}); std::vector<PointerCoords> pointerCoords; pointerCoords.emplace_back().clear(); pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_X, x); pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, y); + pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, dx); + pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, dy); nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC); MotionEvent event; event.initialize(InputEvent::nextId(), /* deviceId */ 1, AINPUT_SOURCE_TOUCHSCREEN, @@ -672,7 +677,8 @@ MotionEvent createTouchDownEvent(int x, int y, ui::Transform transform) { /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, transform, /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, /* displayWidth */ 400, + AMOTION_EVENT_INVALID_CURSOR_POSITION, displayOrientation, + /* displayWidth */ 400, /* displayHeight */ 800, eventTime, eventTime, pointerCoords.size(), pointerProperties.data(), pointerCoords.data()); return event; @@ -683,26 +689,56 @@ TEST_F(MotionEventTest, ApplyTransform) { ui::Transform identity; ui::Transform xform(ui::Transform::ROT_90, 800, 400); xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, xform); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); ASSERT_EQ(700, event.getRawX(0)); ASSERT_EQ(60, event.getRawY(0)); ASSERT_NE(event.getRawX(0), event.getX(0)); ASSERT_NE(event.getRawY(0), event.getY(0)); + // Relative values should be rotated but not translated. + ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - MotionEvent changedEvent = createTouchDownEvent(60, 100, identity); + MotionEvent changedEvent = createTouchDownEvent(60, 100, 42, 96, identity); const std::array<float, 9> rowMajor{xform[0][0], xform[1][0], xform[2][0], xform[0][1], xform[1][1], xform[2][1], xform[0][2], xform[1][2], xform[2][2]}; changedEvent.applyTransform(rowMajor); // transformContent effectively rotates the raw coordinates, so those should now include - // both rotation AND offset + // both rotation AND offset. ASSERT_EQ(720, changedEvent.getRawX(0)); ASSERT_EQ(100, changedEvent.getRawY(0)); + // Relative values should be rotated but not translated. + ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); - // The transformed output should be the same then + // The transformed output should be the same then. ASSERT_NEAR(event.getX(0), changedEvent.getX(0), 0.001); ASSERT_NEAR(event.getY(0), changedEvent.getY(0), 0.001); + ASSERT_NEAR(event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0), + changedEvent.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0), 0.001); + ASSERT_NEAR(event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0), + changedEvent.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0), 0.001); +} + +TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) { + constexpr static auto NON_POINTER_SOURCES = {AINPUT_SOURCE_TRACKBALL, + AINPUT_SOURCE_MOUSE_RELATIVE, + AINPUT_SOURCE_JOYSTICK}; + for (uint32_t source : NON_POINTER_SOURCES) { + // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). + ui::Transform xform(ui::Transform::ROT_90, 800, 400); + xform.set(xform.tx() + 20, xform.ty() + 40); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); + event.setSource(source); + + // Since this event comes from a non-pointer source, it should include rotation but not + // translation/offset. + ASSERT_EQ(-100, event.getX(0)); + ASSERT_EQ(60, event.getY(0)); + ASSERT_EQ(event.getRawX(0), event.getX(0)); + ASSERT_EQ(event.getRawY(0), event.getY(0)); + } } TEST_F(MotionEventTest, RawCompatTransform) { @@ -710,11 +746,14 @@ TEST_F(MotionEventTest, RawCompatTransform) { // Make sure raw is raw regardless of transform translation. ui::Transform xform; xform.set(20, 40); - MotionEvent event = createTouchDownEvent(60, 100, xform); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform); ASSERT_EQ(60, event.getRawX(0)); ASSERT_EQ(100, event.getRawY(0)); ASSERT_NE(event.getRawX(0), event.getX(0)); ASSERT_NE(event.getRawY(0), event.getY(0)); + // Relative values should not be modified. + ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); } // Next check that getRaw contains rotation (for compatibility) but otherwise is still @@ -723,29 +762,50 @@ TEST_F(MotionEventTest, RawCompatTransform) { // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). ui::Transform xform(ui::Transform::ROT_90, 800, 400); xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, xform); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); ASSERT_EQ(700, event.getRawX(0)); ASSERT_EQ(60, event.getRawY(0)); ASSERT_NE(event.getRawX(0), event.getX(0)); ASSERT_NE(event.getRawY(0), event.getY(0)); + // Relative values should be rotated but not translated. + ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); } { // Same as above, but check rotate-180. ui::Transform xform(ui::Transform::ROT_180, 400, 800); xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, xform); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_180); ASSERT_EQ(340, event.getRawX(0)); ASSERT_EQ(700, event.getRawY(0)); + // Relative values should be rotated but not translated. + ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); } { // Same as above, but check rotate-270. ui::Transform xform(ui::Transform::ROT_270, 800, 400); xform.set(xform.tx() + 20, xform.ty() + 40); - MotionEvent event = createTouchDownEvent(60, 100, xform); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_270); ASSERT_EQ(100, event.getRawX(0)); ASSERT_EQ(340, event.getRawY(0)); + // Relative values should be rotated but not translated. + ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); + } + + { + // Finally, check that raw isn't effected by transform + ui::Transform xform(ui::Transform::ROT_270, 800, 400); + xform.set(xform.tx() + 20, xform.ty() + 40); + MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90); + ASSERT_EQ(700, event.getRawX(0)); + ASSERT_EQ(60, event.getRawY(0)); + // Relative values should be rotated but not translated. + ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); + ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); } } @@ -772,9 +832,9 @@ TEST_F(MotionEventTest, Initialize_SetsClassification) { DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/, - pointerCount, pointerProperties, pointerCoords); + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, + 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(classification, event.getClassification()); } } @@ -794,10 +854,9 @@ TEST_F(MotionEventTest, Initialize_SetsCursorPosition) { event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0, - 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, - pointerCoords); + 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/, + pointerCount, pointerProperties, pointerCoords); event.offsetLocation(20, 60); ASSERT_EQ(280, event.getRawXCursorPosition()); ASSERT_EQ(540, event.getRawYCursorPosition()); diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index a2cfaa1cc0..5d1f2c3bfc 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -23,6 +23,7 @@ #include <attestation/HmacKeyManager.h> #include <cutils/ashmem.h> #include <gtest/gtest.h> +#include <gui/constants.h> #include <input/InputTransport.h> #include <utils/StopWatch.h> #include <utils/Timers.h> @@ -162,6 +163,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { constexpr float yPrecision = 0.5; constexpr float xCursorPosition = 1.3; constexpr float yCursorPosition = 50.6; + constexpr uint32_t displayOrientation = ui::Transform::ROT_0; constexpr int32_t displayWidth = 1000; constexpr int32_t displayHeight = 2000; constexpr nsecs_t downTime = 3; @@ -192,9 +194,9 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { status = mPublisher->publishMotionEvent(seq, eventId, deviceId, source, displayId, hmac, action, actionButton, flags, edgeFlags, metaState, buttonState, classification, transform, xPrecision, yPrecision, - xCursorPosition, yCursorPosition, displayWidth, - displayHeight, downTime, eventTime, pointerCount, - pointerProperties, pointerCoords); + xCursorPosition, yCursorPosition, displayOrientation, + displayWidth, displayHeight, downTime, eventTime, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; @@ -231,6 +233,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition()); EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition()); EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition()); + EXPECT_EQ(displayOrientation, motionEvent->getDisplayOrientation()); EXPECT_EQ(displayWidth, motionEvent->getDisplaySize().x); EXPECT_EQ(displayHeight, motionEvent->getDisplaySize().y); EXPECT_EQ(downTime, motionEvent->getDownTime()); @@ -460,8 +463,9 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZer status = mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); + AMOTION_EVENT_INVALID_CURSOR_POSITION, + ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount, + pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -476,8 +480,9 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); + AMOTION_EVENT_INVALID_CURSOR_POSITION, + ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount, + pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -497,8 +502,9 @@ TEST_F(InputPublisherAndConsumerTest, status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); + AMOTION_EVENT_INVALID_CURSOR_POSITION, + ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount, + pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index 5861d55156..59fed1fb41 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -74,10 +74,10 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 124); CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 128); CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 132); - CHECK_OFFSET(InputMessage::Body::Motion, displayWidth, 136); - CHECK_OFFSET(InputMessage::Body::Motion, displayHeight, 140); - CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 144); - CHECK_OFFSET(InputMessage::Body::Motion, empty3, 148); + CHECK_OFFSET(InputMessage::Body::Motion, displayOrientation, 136); + CHECK_OFFSET(InputMessage::Body::Motion, displayWidth, 140); + CHECK_OFFSET(InputMessage::Body::Motion, displayHeight, 144); + CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 148); CHECK_OFFSET(InputMessage::Body::Motion, pointers, 152); CHECK_OFFSET(InputMessage::Body::Focus, eventId, 0); diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index aefc2ec47d..13e2b02ca4 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -23,6 +23,7 @@ #include <android-base/stringprintf.h> #include <attestation/HmacKeyManager.h> #include <gtest/gtest.h> +#include <gui/constants.h> #include <input/VelocityTracker.h> using namespace std::chrono_literals; @@ -183,8 +184,8 @@ static std::vector<MotionEvent> createMotionEventStream( AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, identityTransform, 0 /*xPrecision*/, 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, 0 /*downTime*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, entry.eventTime.count(), pointerCount, properties, coords); events.emplace_back(event); diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp index f79098c63c..b29c9a4877 100644 --- a/libs/input/tests/VerifiedInputEvent_test.cpp +++ b/libs/input/tests/VerifiedInputEvent_test.cpp @@ -16,6 +16,7 @@ #include <attestation/HmacKeyManager.h> #include <gtest/gtest.h> +#include <gui/constants.h> #include <input/Input.h> namespace android { @@ -46,10 +47,9 @@ static MotionEvent getMotionEventWithFlags(int32_t flags) { INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, transform, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/, - 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - 100 /*downTime*/, 200 /*eventTime*/, pointerCount, pointerProperties, - pointerCoords); + 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 100 /*downTime*/, + 200 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); return event; } diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index 0edb213089..2dd6c4fcaa 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -20,7 +20,6 @@ #include <android-base/thread_annotations.h> #include <gui/DisplayEventDispatcher.h> #include <gui/ISurfaceComposer.h> -#include <gui/SurfaceComposerClient.h> #include <jni.h> #include <private/android/choreographer.h> #include <utils/Looper.h> diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 4cb1b4259b..14627ce0ce 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -71,7 +71,7 @@ public: void cleanupPostRender() override; int getContextPriority() override; bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } - void onPrimaryDisplaySizeChanged(ui::Size size) override {} + void onActiveDisplaySizeChanged(ui::Size size) override {} EGLDisplay getEGLDisplay() const { return mEGLDisplay; } // Creates an output image for rendering to diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 5964bc3927..967cf5deff 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -129,9 +129,9 @@ public: // Attempt to switch RenderEngine into and out of protectedContext mode virtual void useProtectedContext(bool useProtectedContext) = 0; - // Notify RenderEngine of changes to the dimensions of the primary display + // Notify RenderEngine of changes to the dimensions of the active display // so that it can configure its internal caches accordingly. - virtual void onPrimaryDisplaySizeChanged(ui::Size size) = 0; + virtual void onActiveDisplaySizeChanged(ui::Size size) = 0; // Renders layers for a particular display via GPU composition. This method // should be called for every display that needs to be rendered via the GPU. diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index a4aa9ea488..0be3ba6b11 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -54,7 +54,7 @@ public: MOCK_METHOD0(cleanFramebufferCache, void()); MOCK_METHOD0(getContextPriority, int()); MOCK_METHOD0(supportsBackgroundBlur, bool()); - MOCK_METHOD1(onPrimaryDisplaySizeChanged, void(ui::Size)); + MOCK_METHOD1(onActiveDisplaySizeChanged, void(ui::Size)); protected: // mock renderengine still needs to implement these, but callers should never need to call them. diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 3c59f11395..f4b07d06a5 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -1398,7 +1398,7 @@ int SkiaGLRenderEngine::getContextPriority() { return value; } -void SkiaGLRenderEngine::onPrimaryDisplaySizeChanged(ui::Size size) { +void SkiaGLRenderEngine::onActiveDisplaySizeChanged(ui::Size size) { // This cache multiplier was selected based on review of cache sizes relative // to the screen resolution. Looking at the worst case memory needed by blur (~1.5x), // shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index a852bbcaf8..cc91948ac9 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -67,7 +67,7 @@ public: void useProtectedContext(bool useProtectedContext) override; bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } void assertShadersCompiled(int numShaders) override; - void onPrimaryDisplaySizeChanged(ui::Size size) override; + void onActiveDisplaySizeChanged(ui::Size size) override; int reportShadersCompiled() override; protected: diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index b9dabc1d05..8e666d5733 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -361,14 +361,14 @@ bool RenderEngineThreaded::supportsBackgroundBlur() { return mRenderEngine->supportsBackgroundBlur(); } -void RenderEngineThreaded::onPrimaryDisplaySizeChanged(ui::Size size) { +void RenderEngineThreaded::onActiveDisplaySizeChanged(ui::Size size) { // This function is designed so it can run asynchronously, so we do not need to wait // for the futures. { std::lock_guard lock(mThreadMutex); mFunctionCalls.push([size](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::onPrimaryDisplaySizeChanged"); - instance.onPrimaryDisplaySizeChanged(size); + ATRACE_NAME("REThreaded::onActiveDisplaySizeChanged"); + instance.onActiveDisplaySizeChanged(size); }); } mCondition.notify_one(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index f2f5c0f7cd..b197df7e0f 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -65,7 +65,7 @@ public: void cleanFramebufferCache() override; int getContextPriority() override; bool supportsBackgroundBlur() override; - void onPrimaryDisplaySizeChanged(ui::Size size) override; + void onActiveDisplaySizeChanged(ui::Size size) override; protected: void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override; diff --git a/libs/vibrator/ExternalVibrationUtils.cpp b/libs/vibrator/ExternalVibrationUtils.cpp index 749c568457..980b08ba36 100644 --- a/libs/vibrator/ExternalVibrationUtils.cpp +++ b/libs/vibrator/ExternalVibrationUtils.cpp @@ -56,6 +56,36 @@ float getHapticMaxAmplitudeRatio(HapticScale scale) { } } +void applyHapticScale(float* buffer, size_t length, HapticScale scale) { + if (scale == HapticScale::MUTE) { + memset(buffer, 0, length * sizeof(float)); + return; + } + if (scale == HapticScale::NONE) { + return; + } + float gamma = getHapticScaleGamma(scale); + float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(scale); + for (size_t i = 0; i < length; i++) { + float sign = buffer[i] >= 0 ? 1.0 : -1.0; + buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma) + * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign; + } +} + +void clipHapticData(float* buffer, size_t length, float limit) { + if (isnan(limit) || limit == 0) { + return; + } + limit = fabsf(limit); + for (size_t i = 0; i < length; i++) { + float sign = buffer[i] >= 0 ? 1.0 : -1.0; + if (fabsf(buffer[i]) > limit) { + buffer[i] = limit * sign; + } + } +} + } // namespace bool isValidHapticScale(HapticScale scale) { @@ -71,21 +101,11 @@ bool isValidHapticScale(HapticScale scale) { return false; } -void scaleHapticData(float* buffer, size_t length, HapticScale scale) { - if (!isValidHapticScale(scale) || scale == HapticScale::NONE) { - return; - } - if (scale == HapticScale::MUTE) { - memset(buffer, 0, length * sizeof(float)); - return; - } - float gamma = getHapticScaleGamma(scale); - float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(scale); - for (size_t i = 0; i < length; i++) { - float sign = buffer[i] >= 0 ? 1.0 : -1.0; - buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma) - * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign; +void scaleHapticData(float* buffer, size_t length, HapticScale scale, float limit) { + if (isValidHapticScale(scale)) { + applyHapticScale(buffer, length, scale); } + clipHapticData(buffer, length, limit); } } // namespace android::os diff --git a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h index 20045d0769..84357fcb35 100644 --- a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h +++ b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h @@ -32,7 +32,11 @@ enum class HapticScale { bool isValidHapticScale(HapticScale scale); -void scaleHapticData(float* buffer, size_t length, HapticScale scale); +/* Scales the haptic data in given buffer using the selected HapticScale and ensuring no absolute + * value will be larger than the absolute of given limit. + * The limit will be ignored if it is NaN or zero. + */ +void scaleHapticData(float* buffer, size_t length, HapticScale scale, float limit); } // namespace android::os |