diff options
35 files changed, 837 insertions, 351 deletions
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index 712adfa57b..1fec08027f 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -101,7 +101,7 @@ enum class InputDeviceSensorReportingMode : int32_t { }; enum class InputDeviceLightType : int32_t { - SINGLE = 0, + MONO = 0, PLAYER_ID = 1, RGB = 2, MULTI_COLOR = 3, diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index c605e67853..445df9eeff 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -614,12 +614,6 @@ void IPCThreadState::processPostWriteDerefs() mPostWriteStrongDerefs.clear(); } -void IPCThreadState::createTransactionReference(RefBase* ref) -{ - ref->incStrong(mProcess.get()); - mPostWriteStrongDerefs.push(ref); -} - void IPCThreadState::joinThreadPool(bool isMain) { LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid()); diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 4fd0dc7715..bade9187ac 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -401,7 +401,7 @@ static int open_driver(const char *driver) uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION; result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable); if (result == -1) { - ALOGI("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno)); + ALOGD("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno)); } } else { ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno)); diff --git a/libs/binder/aidl/android/content/pm/OWNERS b/libs/binder/aidl/android/content/pm/OWNERS index b99ca09674..31005184bf 100644 --- a/libs/binder/aidl/android/content/pm/OWNERS +++ b/libs/binder/aidl/android/content/pm/OWNERS @@ -1,4 +1,5 @@ narayan@google.com patb@google.com svetoslavganov@google.com -toddke@google.com
\ No newline at end of file +toddke@google.com +patb@google.com
\ No newline at end of file diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index 5d04ebedae..196a41ba55 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -162,12 +162,6 @@ public: // This constant needs to be kept in sync with Binder.UNSET_WORKSOURCE from the Java // side. static const int32_t kUnsetWorkSource = -1; - - // Create a temp reference until commands in queue flushed to driver - // Internal only. - // @internal - void createTransactionReference(RefBase* ref); - private: IPCThreadState(); ~IPCThreadState(); diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 0c3fbcd2da..5612d1db66 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -30,7 +30,6 @@ #include <binder/IBinder.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> -#include <binder/ParcelRef.h> #include <linux/sched.h> #include <sys/epoll.h> @@ -891,36 +890,6 @@ TEST_F(BinderLibTest, FreedBinder) { } } -TEST_F(BinderLibTest, ParcelAllocatedOnAnotherThread) { - sp<IBinder> server = addServer(); - ASSERT_TRUE(server != nullptr); - - Parcel data; - sp<ParcelRef> reply = ParcelRef::create(); - - // when we have a Parcel which is deleted on another thread, if it gets - // deleted, it will tell the kernel this, and it will drop strong references - // to binder, so that we can't BR_ACQUIRE would fail - IPCThreadState::self()->createTransactionReference(reply.get()); - ASSERT_EQ(NO_ERROR, server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, - data, - reply.get())); - - // we have sp to binder, but it is not actually acquired by kernel, the - // transaction is sitting on an out buffer - sp<IBinder> binder = reply->readStrongBinder(); - - std::thread([&] { - // without the transaction reference, this would cause the Parcel to be - // deallocated before the first thread flushes BR_ACQUIRE - reply = nullptr; - IPCThreadState::self()->flushCommands(); - }).join(); - - ASSERT_NE(nullptr, binder); - ASSERT_EQ(NO_ERROR, binder->pingBinder()); -} - TEST_F(BinderLibTest, CheckNoHeaderMappedInUser) { Parcel data, reply; sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack(); diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 53721cf6f7..71e18a97c9 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -824,6 +824,36 @@ public: return error; } + virtual status_t addTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) { + Parcel data, reply; + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); + + const status_t error = + remote()->transact(BnSurfaceComposer::ADD_TUNNEL_MODE_ENABLED_LISTENER, data, + &reply); + if (error != NO_ERROR) { + ALOGE("addTunnelModeEnabledListener: Failed to transact"); + } + return error; + } + + virtual status_t removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) { + Parcel data, reply; + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); + + const status_t error = + remote()->transact(BnSurfaceComposer::REMOVE_TUNNEL_MODE_ENABLED_LISTENER, data, + &reply); + if (error != NO_ERROR) { + ALOGE("removeTunnelModeEnabledListener: Failed to transact"); + } + return error; + } + status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, ui::DisplayModeId defaultMode, bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, @@ -1740,6 +1770,26 @@ status_t BnSurfaceComposer::onTransact( } return removeFpsListener(listener); } + case ADD_TUNNEL_MODE_ENABLED_LISTENER: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<gui::ITunnelModeEnabledListener> listener; + status_t result = data.readNullableStrongBinder(&listener); + if (result != NO_ERROR) { + ALOGE("addTunnelModeEnabledListener: Failed to read listener"); + return result; + } + return addTunnelModeEnabledListener(listener); + } + case REMOVE_TUNNEL_MODE_ENABLED_LISTENER: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<gui::ITunnelModeEnabledListener> listener; + status_t result = data.readNullableStrongBinder(&listener); + if (result != NO_ERROR) { + ALOGE("removeTunnelModeEnabledListener: Failed to read listener"); + return result; + } + return removeTunnelModeEnabledListener(listener); + } case SET_DESIRED_DISPLAY_MODE_SPECS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<IBinder> displayToken = data.readStrongBinder(); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index d27d1ecdbe..e117d1189c 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1268,8 +1268,11 @@ int Surface::query(int what, int* value) const { if (err == NO_ERROR) { return NO_ERROR; } - if (composerService()->authenticateSurfaceTexture( - mGraphicBufferProducer)) { + sp<ISurfaceComposer> surfaceComposer = composerService(); + if (surfaceComposer == nullptr) { + return -EPERM; // likely permissions error + } + if (surfaceComposer->authenticateSurfaceTexture(mGraphicBufferProducer)) { *value = 1; } else { *value = 0; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index aa938087e8..371454a3de 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -65,12 +65,12 @@ ComposerService::ComposerService() connectLocked(); } -void ComposerService::connectLocked() { +bool ComposerService::connectLocked() { const String16 name("SurfaceFlinger"); - while (getService(name, &mComposerService) != NO_ERROR) { - usleep(250000); + mComposerService = waitForService<ISurfaceComposer>(name); + if (mComposerService == nullptr) { + return false; // fatal error or permission problem } - assert(mComposerService != nullptr); // Create the death listener. class DeathObserver : public IBinder::DeathRecipient { @@ -86,15 +86,16 @@ void ComposerService::connectLocked() { mDeathObserver = new DeathObserver(*const_cast<ComposerService*>(this)); IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver); + return true; } /*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() { ComposerService& instance = ComposerService::getInstance(); Mutex::Autolock _l(instance.mLock); if (instance.mComposerService == nullptr) { - ComposerService::getInstance().connectLocked(); - assert(instance.mComposerService != nullptr); - ALOGD("ComposerService reconnected"); + if (ComposerService::getInstance().connectLocked()) { + ALOGD("ComposerService reconnected"); + } } return instance.mComposerService; } @@ -2077,6 +2078,16 @@ status_t SurfaceComposerClient::removeFpsListener(const sp<gui::IFpsListener>& l return ComposerService::getComposerService()->removeFpsListener(listener); } +status_t SurfaceComposerClient::addTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) { + return ComposerService::getComposerService()->addTunnelModeEnabledListener(listener); +} + +status_t SurfaceComposerClient::removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) { + return ComposerService::getComposerService()->removeTunnelModeEnabledListener(listener); +} + bool SurfaceComposerClient::getDisplayBrightnessSupport(const sp<IBinder>& displayToken) { bool support = false; ComposerService::getComposerService()->getDisplayBrightnessSupport(displayToken, &support); diff --git a/libs/binder/include/binder/ParcelRef.h b/libs/gui/aidl/android/gui/ITunnelModeEnabledListener.aidl index 497da2d215..2a89ccacec 100644 --- a/libs/binder/include/binder/ParcelRef.h +++ b/libs/gui/aidl/android/gui/ITunnelModeEnabledListener.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * 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. @@ -14,30 +14,16 @@ * limitations under the License. */ -#pragma once +package android.gui; +/** @hide */ +oneway interface ITunnelModeEnabledListener { -#include <binder/Parcel.h> -#include <utils/RefBase.h> - -// --------------------------------------------------------------------------- -namespace android { - -/** - * internal use only - * @internal - */ -class ParcelRef : public Parcel, public RefBase -{ -public: - static sp<ParcelRef> create() { - return new ParcelRef(); - } - -private: - ParcelRef() = default; -}; - -} // namespace android - -// ---------------------------------------------------------------------------
\ No newline at end of file + /** + * Called when tunnel mode status has changed. Tunnel mode is: + * - enabled when there is a sideband stream attached to one of the layers in + * surface flinger + * - disabled when there is no layer with a sideband stream + */ + void onTunnelModeEnabledChanged(boolean enabled); +} diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index cb0468901a..439d90ad10 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -21,6 +21,7 @@ #include <android/gui/IHdrLayerInfoListener.h> #include <android/gui/IScreenCaptureListener.h> #include <android/gui/ITransactionTraceListener.h> +#include <android/gui/ITunnelModeEnabledListener.h> #include <binder/IBinder.h> #include <binder/IInterface.h> #include <gui/FrameTimelineInfo.h> @@ -377,6 +378,21 @@ public: */ virtual status_t removeFpsListener(const sp<gui::IFpsListener>& listener) = 0; + /* Registers a listener to receive tunnel mode enabled updates from SurfaceFlinger. + * + * Requires ACCESS_SURFACE_FLINGER permission. + */ + virtual status_t addTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) = 0; + + /* + * Removes a listener that was receiving tunnel mode enabled updates from SurfaceFlinger. + * + * Requires ACCESS_SURFACE_FLINGER permission. + */ + virtual status_t removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) = 0; + /* Sets the refresh rate boundaries for the display. * * The primary refresh rate range represents display manager's general guidance on the display @@ -607,6 +623,8 @@ public: ADD_HDR_LAYER_INFO_LISTENER, REMOVE_HDR_LAYER_INFO_LISTENER, ON_PULL_ATOM, + ADD_TUNNEL_MODE_ENABLED_LISTENER, + REMOVE_TUNNEL_MODE_ENABLED_LISTENER, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 0940e9d178..2582882c85 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -50,6 +50,7 @@ class HdrCapabilities; class ISurfaceComposerClient; class IGraphicBufferProducer; class IRegionSamplingListener; +class ITunnelModeEnabledListener; class Region; struct SurfaceControlStats { @@ -610,6 +611,10 @@ public: static status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener); static status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener); static status_t removeFpsListener(const sp<gui::IFpsListener>& listener); + static status_t addTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener); + static status_t removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener); private: virtual void onFirstRef(); diff --git a/services/surfaceflinger/TraceUtils.h b/libs/gui/include/gui/TraceUtils.h index 90a34a5ed8..b9ec14aaf0 100644 --- a/services/surfaceflinger/TraceUtils.h +++ b/libs/gui/include/gui/TraceUtils.h @@ -14,9 +14,6 @@ * limitations under the License. */ -// TODO(b/183120308): This file is a copy of f/b/libs/hwui/utils/TraceUtils.h -// It should be migrated to a common place where both SF and hwui could use it. - #pragma once #include <cutils/trace.h> diff --git a/libs/gui/include/private/gui/ComposerService.h b/libs/gui/include/private/gui/ComposerService.h index 50bd742b6a..fa1071a4e3 100644 --- a/libs/gui/include/private/gui/ComposerService.h +++ b/libs/gui/include/private/gui/ComposerService.h @@ -45,13 +45,12 @@ class ComposerService : public Singleton<ComposerService> Mutex mLock; ComposerService(); - void connectLocked(); + bool connectLocked(); void composerServiceDied(); friend class Singleton<ComposerService>; public: - // Get a connection to the Composer Service. This will block until - // a connection is established. + // a connection is established. Returns null if permission is denied. static sp<ISurfaceComposer> getComposerService(); }; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index ea8c2957a1..b8d34c3160 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -845,6 +845,16 @@ public: return NO_ERROR; } status_t removeFpsListener(const sp<gui::IFpsListener>& /*listener*/) { return NO_ERROR; } + + status_t addTunnelModeEnabledListener(const sp<gui::ITunnelModeEnabledListener>& /*listener*/) { + return NO_ERROR; + } + + status_t removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& /*listener*/) { + return NO_ERROR; + } + status_t setDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/, ui::DisplayModeId /*defaultMode*/, bool /*allowGroupSwitching*/, diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 649a14087e..70ed438112 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -39,6 +39,60 @@ using android::base::StringPrintf; namespace android { +namespace { + +float transformAngle(const ui::Transform& transform, float angleRadians) { + // Construct and transform a vector oriented at the specified clockwise angle from vertical. + // Coordinate system: down is increasing Y, right is increasing X. + float x = sinf(angleRadians); + float y = -cosf(angleRadians); + vec2 transformedPoint = transform.transform(x, y); + + // Determine how the origin is transformed by the matrix so that we + // can transform orientation vectors. + const vec2 origin = transform.transform(0, 0); + + transformedPoint.x -= origin.x; + transformedPoint.y -= origin.y; + + // Derive the transformed vector's clockwise angle from vertical. + float result = atan2f(transformedPoint.x, -transformedPoint.y); + if (result < -M_PI_2) { + result += M_PI; + } else if (result > M_PI_2) { + result -= M_PI; + } + return result; +} + +// Rotates the given point to the transform's 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, + 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}; + } + + vec2 xy(x, y); + if (orientation == ui::Transform::ROT_90) { + xy.x = displayHeight - y; + xy.y = x; + } else if (orientation == ui::Transform::ROT_180) { + xy.x = displayWidth - x; + xy.y = displayHeight - y; + } else if (orientation == ui::Transform::ROT_270) { + xy.x = y; + xy.y = displayWidth - x; + } + return xy; +} + +} // namespace + const char* motionClassificationToString(MotionClassification classification) { switch (classification) { case MotionClassification::NONE: @@ -315,9 +369,14 @@ void PointerCoords::copyFrom(const PointerCoords& other) { } void PointerCoords::transform(const ui::Transform& transform) { - vec2 newCoords = transform.transform(getX(), getY()); - setAxisValue(AMOTION_EVENT_AXIS_X, newCoords.x); - setAxisValue(AMOTION_EVENT_AXIS_Y, newCoords.y); + const vec2 xy = transform.transform(getXYValue()); + setAxisValue(AMOTION_EVENT_AXIS_X, xy.x); + setAxisValue(AMOTION_EVENT_AXIS_Y, xy.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)); + } } // --- PointerProperties --- @@ -444,45 +503,32 @@ const PointerCoords* MotionEvent::getHistoricalRawPointerCoords( } float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, - size_t historicalIndex) const { - if (axis != AMOTION_EVENT_AXIS_X && axis != AMOTION_EVENT_AXIS_Y) { - return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); - } - // 0x7 encapsulates all 3 rotations (see ui::Transform::RotationFlags) - static const int ALL_ROTATIONS_MASK = 0x7; - uint32_t orientation = (mTransform.getOrientation() & ALL_ROTATIONS_MASK); - if (orientation == ui::Transform::ROT_0) { - return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); - } + size_t historicalIndex) const { + const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex); - // For compatibility, convert raw coordinates into "oriented screen space". Once app developers - // are educated about getRaw, we can consider removing this. - vec2 xy = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getXYValue(); - const float unrotatedX = xy.x; - if (orientation == ui::Transform::ROT_90) { - xy.x = mDisplayHeight - xy.y; - xy.y = unrotatedX; - } else if (orientation == ui::Transform::ROT_180) { - xy.x = mDisplayWidth - xy.x; - xy.y = mDisplayHeight - xy.y; - } else if (orientation == ui::Transform::ROT_270) { - xy.x = xy.y; - xy.y = mDisplayWidth - unrotatedX; + 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); + static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); + return xy[axis]; } - static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); - return xy[axis]; + + return coords->getAxisValue(axis); } float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const { - if (axis != AMOTION_EVENT_AXIS_X && axis != AMOTION_EVENT_AXIS_Y) { - return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); + const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex); + + if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) { + const vec2 xy = mTransform.transform(coords->getXYValue()); + static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); + return xy[axis]; } - vec2 vals = mTransform.transform( - getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getXYValue()); - static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1); - return vals[axis]; + return coords->getAxisValue(axis); } ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { @@ -513,78 +559,30 @@ void MotionEvent::scale(float globalScaleFactor) { } } -static vec2 transformPoint(const std::array<float, 9>& matrix, float x, float y) { - // Apply perspective transform like Skia. - float newX = matrix[0] * x + matrix[1] * y + matrix[2]; - float newY = matrix[3] * x + matrix[4] * y + matrix[5]; - float newZ = matrix[6] * x + matrix[7] * y + matrix[8]; - if (newZ) { - newZ = 1.0f / newZ; - } - vec2 transformedPoint; - transformedPoint.x = newX * newZ; - transformedPoint.y = newY * newZ; - return transformedPoint; -} - -static float transformAngle(const std::array<float, 9>& matrix, float angleRadians, float originX, - float originY) { - // Construct and transform a vector oriented at the specified clockwise angle from vertical. - // Coordinate system: down is increasing Y, right is increasing X. - float x = sinf(angleRadians); - float y = -cosf(angleRadians); - vec2 transformedPoint = transformPoint(matrix, x, y); - - transformedPoint.x -= originX; - transformedPoint.y -= originY; - - // Derive the transformed vector's clockwise angle from vertical. - float result = atan2f(transformedPoint.x, -transformedPoint.y); - if (result < - M_PI_2) { - result += M_PI; - } else if (result > M_PI_2) { - result -= M_PI; - } - return result; -} - void MotionEvent::transform(const std::array<float, 9>& matrix) { - // We want to preserve the rawX and rawY so we just update the transform - // using the values of the transform passed in + // We want to preserve the raw axes values stored in the PointerCoords, so we just update the + // transform using the values passed in. ui::Transform newTransform; newTransform.set(matrix); mTransform = newTransform * mTransform; - // Determine how the origin is transformed by the matrix so that we - // can transform orientation vectors. - vec2 origin = transformPoint(matrix, 0, 0); - - // Apply the transformation to all samples. - size_t numSamples = mSamplePointerCoords.size(); - for (size_t i = 0; i < numSamples; i++) { - PointerCoords& c = mSamplePointerCoords.editItemAt(i); - float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); - c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, - transformAngle(matrix, orientation, origin.x, origin.y)); - } + // We need to update the AXIS_ORIENTATION value here to maintain the old behavior where the + // orientation angle is not affected by the initial transformation set in the MotionEvent. + std::for_each(mSamplePointerCoords.begin(), mSamplePointerCoords.end(), + [&newTransform](PointerCoords& c) { + float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); + c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, + transformAngle(newTransform, orientation)); + }); } void MotionEvent::applyTransform(const std::array<float, 9>& matrix) { - // Determine how the origin is transformed by the matrix so that we - // can transform orientation vectors. - vec2 origin = transformPoint(matrix, 0, 0); + ui::Transform transform; + transform.set(matrix); // Apply the transformation to all samples. - size_t numSamples = mSamplePointerCoords.size(); - for (size_t i = 0; i < numSamples; i++) { - PointerCoords& c = mSamplePointerCoords.editItemAt(i); - float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); - c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, - transformAngle(matrix, orientation, origin.x, origin.y)); - vec2 xy = transformPoint(matrix, c.getX(), c.getY()); - c.setAxisValue(AMOTION_EVENT_AXIS_X, xy.x); - c.setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y); - } + std::for_each(mSamplePointerCoords.begin(), mSamplePointerCoords.end(), + [&transform](PointerCoords& c) { c.transform(transform); }); } #ifdef __linux__ diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 9f6ecaa1a0..47c330ffb1 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -725,6 +725,14 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, return BAD_VALUE; } + // setup color filter if necessary + sk_sp<SkColorFilter> displayColorTransform; + if (display.colorTransform != mat4()) { + displayColorTransform = SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)); + } + const bool ctModifiesAlpha = + displayColorTransform && !displayColorTransform->isAlphaUnchanged(); + // Find if any layers have requested blur, we'll use that info to decide when to render to an // offscreen buffer and when to render to the native buffer. sk_sp<SkSurface> activeSurface(dstSurface); @@ -734,6 +742,10 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, if (mBlurFilter) { bool requiresCompositionLayer = false; for (const auto& layer : layers) { + // if the layer doesn't have blur or it is not visible then continue + if (!layerHasBlur(layer, ctModifiesAlpha)) { + continue; + } if (layer->backgroundBlurRadius > 0 && layer->backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) { requiresCompositionLayer = true; @@ -779,12 +791,6 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, canvas->drawRegion(clearRegion, paint); } - // setup color filter if necessary - sk_sp<SkColorFilter> displayColorTransform; - if (display.colorTransform != mat4()) { - displayColorTransform = SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)); - } - for (const auto& layer : layers) { ATRACE_NAME("DrawLayer"); @@ -850,7 +856,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, const auto [bounds, roundRectClip] = getBoundsAndClip(layer->geometry.boundaries, layer->geometry.roundedCornersCrop, layer->geometry.roundedCornersRadius); - if (mBlurFilter && layerHasBlur(layer)) { + if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) { std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs; // if multiple layers have blur, then we need to take a snapshot now because @@ -1188,8 +1194,15 @@ inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(const Fl return {SkRRect::MakeRect(bounds), clip}; } -inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings* layer) { - return layer->backgroundBlurRadius > 0 || layer->blurRegions.size(); +inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings* layer, + bool colorTransformModifiesAlpha) { + if (layer->backgroundBlurRadius > 0 || layer->blurRegions.size()) { + // return false if the content is opaque and would therefore occlude the blur + const bool opaqueContent = !layer->source.buffer.buffer || layer->source.buffer.isOpaque; + const bool opaqueAlpha = layer->alpha == 1.0f && !colorTransformModifiesAlpha; + return layer->skipContentDraw || !(opaqueContent && opaqueAlpha); + } + return false; } inline SkColor SkiaGLRenderEngine::getSkColor(const vec4& color) { diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 4265c08a3f..97d3b72347 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -90,7 +90,7 @@ private: inline SkRect getSkRect(const Rect& layer); inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const FloatRect& bounds, const FloatRect& crop, float cornerRadius); - inline bool layerHasBlur(const LayerSettings* layer); + inline bool layerHasBlur(const LayerSettings* layer, bool colorTransformModifiesAlpha); inline SkColor getSkColor(const vec4& color); inline SkM44 getSkM44(const mat4& matrix); inline SkPoint3 getSkPoint3(const vec3& vector); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 790bd096e6..7e069c80d0 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -89,6 +89,14 @@ using com::android::internal::compat::IPlatformCompatNative; namespace android::inputdispatcher { +// When per-window-input-rotation is enabled, InputFlinger works in the un-rotated display +// coordinates and SurfaceFlinger includes the display rotation in the input window transforms. +static bool isPerWindowInputRotationEnabled() { + static const bool PER_WINDOW_INPUT_ROTATION = + base::GetBoolProperty("persist.debug.per_window_input_rotation", false); + return PER_WINDOW_INPUT_ROTATION; +} + // Default input dispatching timeout if there is no focused application or paused window // from which to determine an appropriate dispatching timeout. const std::chrono::duration DEFAULT_INPUT_DISPATCHING_TIMEOUT = std::chrono::milliseconds( @@ -4491,6 +4499,13 @@ void InputDispatcher::setInputWindowsLocked( // Copy old handles for release if they are no longer present. const std::vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId); + // Save the old windows' orientation by ID before it gets updated. + std::unordered_map<int32_t, uint32_t> oldWindowOrientations; + for (const sp<InputWindowHandle>& handle : oldWindowHandles) { + oldWindowOrientations.emplace(handle->getId(), + handle->getInfo()->transform.getOrientation()); + } + updateWindowHandlesForDisplayLocked(inputWindowHandles, displayId); const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId); @@ -4539,6 +4554,25 @@ void InputDispatcher::setInputWindowsLocked( } } + if (isPerWindowInputRotationEnabled()) { + // Determine if the orientation of any of the input windows have changed, and cancel all + // pointer events if necessary. + for (const sp<InputWindowHandle>& oldWindowHandle : oldWindowHandles) { + const sp<InputWindowHandle> newWindowHandle = getWindowHandleLocked(oldWindowHandle); + if (newWindowHandle != nullptr && + newWindowHandle->getInfo()->transform.getOrientation() != + oldWindowOrientations[oldWindowHandle->getId()]) { + std::shared_ptr<InputChannel> inputChannel = + getInputChannelLocked(newWindowHandle->getToken()); + if (inputChannel != nullptr) { + CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, + "touched window's orientation changed"); + synthesizeCancelationEventsForInputChannelLocked(inputChannel, options); + } + } + } + } + // Release information for windows that are no longer present. // This ensures that unused input channels are released promptly. // Otherwise, they might stick around until the window handle is destroyed diff --git a/services/inputflinger/reader/controller/PeripheralController.cpp b/services/inputflinger/reader/controller/PeripheralController.cpp index 1a40d06f45..16251ee0ca 100644 --- a/services/inputflinger/reader/controller/PeripheralController.cpp +++ b/services/inputflinger/reader/controller/PeripheralController.cpp @@ -104,7 +104,7 @@ void PeripheralController::Light::setRawLightBrightness(int32_t rawLightId, int3 context.setLightBrightness(rawLightId, brightness); } -bool PeripheralController::SingleLight::setLightColor(int32_t color) { +bool PeripheralController::MonoLight::setLightColor(int32_t color) { int32_t brightness = getAlpha(color); setRawLightBrightness(rawId, brightness); @@ -148,7 +148,7 @@ bool PeripheralController::MultiColorLight::setLightColor(int32_t color) { return true; } -std::optional<int32_t> PeripheralController::SingleLight::getLightColor() { +std::optional<int32_t> PeripheralController::MonoLight::getLightColor() { std::optional<int32_t> brightness = getRawLightBrightness(rawId); if (!brightness.has_value()) { return std::nullopt; @@ -234,7 +234,7 @@ std::optional<int32_t> PeripheralController::PlayerIdLight::getLightPlayerId() { return std::nullopt; } -void PeripheralController::SingleLight::dump(std::string& dump) { +void PeripheralController::MonoLight::dump(std::string& dump) { dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0)); } @@ -423,7 +423,7 @@ void PeripheralController::configureLights() { playerIdLightIds); mLights.insert_or_assign(light->id, std::move(light)); // Remove these raw lights from raw light info as they've been used to compose a - // Player ID light, so we do not expose these raw lights as single lights. + // Player ID light, so we do not expose these raw lights as mono lights. for (const auto& [playerId, rawId] : playerIdLightIds) { rawInfos.erase(rawId); } @@ -460,13 +460,12 @@ void PeripheralController::configureLights() { mLights.insert_or_assign(light->id, std::move(light)); continue; } - // Construct a single LED light + // Construct a Mono LED light if (DEBUG_LIGHT_DETAILS) { - ALOGD("Single light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str()); + ALOGD("Mono light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str()); } - std::unique_ptr<Light> light = - std::make_unique<SingleLight>(getDeviceContext(), rawInfo.name, ++mNextId, - rawInfo.id); + std::unique_ptr<Light> light = std::make_unique<MonoLight>(getDeviceContext(), rawInfo.name, + ++mNextId, rawInfo.id); mLights.insert_or_assign(light->id, std::move(light)); } diff --git a/services/inputflinger/reader/controller/PeripheralController.h b/services/inputflinger/reader/controller/PeripheralController.h index ff3607f6c1..b1bc8c732c 100644 --- a/services/inputflinger/reader/controller/PeripheralController.h +++ b/services/inputflinger/reader/controller/PeripheralController.h @@ -78,10 +78,10 @@ private: void setRawLightBrightness(int32_t rawLightId, int32_t brightness); }; - struct SingleLight : public Light { - explicit SingleLight(InputDeviceContext& context, const std::string& name, int32_t id, - int32_t rawId) - : Light(context, name, id, InputDeviceLightType::SINGLE), rawId(rawId) {} + struct MonoLight : public Light { + explicit MonoLight(InputDeviceContext& context, const std::string& name, int32_t id, + int32_t rawId) + : Light(context, name, id, InputDeviceLightType::MONO), rawId(rawId) {} int32_t rawId; bool setLightColor(int32_t color) override; diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index d6bd8237e7..437902a79b 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -188,6 +188,8 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { mOrientation = DISPLAY_ORIENTATION_0; + mDisplayWidth = 0; + mDisplayHeight = 0; const bool isOrientedDevice = (mParameters.orientationAware && mParameters.hasAssociatedDisplay); @@ -202,6 +204,8 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config->getDisplayViewportByType(ViewportType::INTERNAL); if (internalViewport) { mOrientation = getInverseRotation(internalViewport->orientation); + mDisplayWidth = internalViewport->deviceWidth; + mDisplayHeight = internalViewport->deviceHeight; } } } else { @@ -360,13 +364,19 @@ void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { } mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + if (isPerWindowInputRotationEnabled()) { + // Rotate the cursor position that is in PointerController's rotated coordinate space + // to InputReader's un-rotated coordinate space. + rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/, + mDisplayWidth, mDisplayHeight); + } pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); displayId = mPointerController->getDisplayId(); - } else if (mSource == AINPUT_SOURCE_MOUSE_RELATIVE) { - // Pointer capture mode + } else { + // Pointer capture and navigation modes pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index 9a8ca01294..88e947f7d5 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -105,6 +105,8 @@ private: VelocityControl mWheelYVelocityControl; int32_t mOrientation; + int32_t mDisplayWidth; + int32_t mDisplayHeight; std::shared_ptr<PointerControllerInterface> mPointerController; diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h index 1843b03c59..da0fea4616 100644 --- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h +++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h @@ -68,6 +68,29 @@ static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { *deltaX = -*deltaY; *deltaY = temp; break; + + default: + break; + } +} + +// Rotates the given point (x, y) by the supplied orientation. The width and height are the +// dimensions of the surface prior to this rotation being applied. +static void rotatePoint(int32_t orientation, float& x, float& y, int32_t width, int32_t height) { + rotateDelta(orientation, &x, &y); + switch (orientation) { + case DISPLAY_ORIENTATION_90: + y += width; + break; + case DISPLAY_ORIENTATION_180: + x += width; + y += height; + break; + case DISPLAY_ORIENTATION_270: + x += height; + break; + default: + break; } } diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index fb654847ed..60502384a3 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -28,30 +28,6 @@ namespace android { -namespace { - -// Rotates the given point (x, y) by the supplied orientation. The width and height are the -// dimensions of the surface prior to this rotation being applied. -void rotatePoint(int32_t orientation, float& x, float& y, int32_t width, int32_t height) { - rotateDelta(orientation, &x, &y); - switch (orientation) { - case DISPLAY_ORIENTATION_90: - y += width; - break; - case DISPLAY_ORIENTATION_180: - x += width; - y += height; - break; - case DISPLAY_ORIENTATION_270: - x += height; - break; - default: - break; - } -} - -} // namespace - // --- Constants --- // Maximum amount of latency to add to touch events while waiting for data from an @@ -682,7 +658,9 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { int32_t rawHeight = mRawPointerAxes.getRawHeight(); bool viewportChanged = mViewport != *newViewport; + bool skipViewportUpdate = false; if (viewportChanged) { + bool viewportOrientationChanged = mViewport.orientation != newViewport->orientation; mViewport = *newViewport; if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) { @@ -746,6 +724,8 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { mPhysicalLeft = naturalPhysicalLeft; mPhysicalTop = naturalPhysicalTop; + const int32_t oldSurfaceWidth = mRawSurfaceWidth; + const int32_t oldSurfaceHeight = mRawSurfaceHeight; mRawSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth; mRawSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight; mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth; @@ -763,6 +743,11 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { mSurfaceOrientation = mParameters.orientationAware ? DISPLAY_ORIENTATION_0 : getInverseRotation(mViewport.orientation); + // For orientation-aware devices that work in the un-rotated coordinate space, the + // viewport update should be skipped if it is only a change in the orientation. + skipViewportUpdate = mParameters.orientationAware && + mRawSurfaceWidth == oldSurfaceWidth && + mRawSurfaceHeight == oldSurfaceHeight && viewportOrientationChanged; } else { mSurfaceOrientation = mParameters.orientationAware ? mViewport.orientation : DISPLAY_ORIENTATION_0; @@ -802,7 +787,7 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { mPointerController.reset(); } - if (viewportChanged || deviceModeChanged) { + if ((viewportChanged && !skipViewportUpdate) || deviceModeChanged) { ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, " "display id %d", getDeviceId(), getDeviceName().c_str(), mRawSurfaceWidth, mRawSurfaceHeight, diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 5eaca71c6a..7a11ca7396 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -2768,18 +2768,22 @@ protected: ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Axis: " << axis << " Source: " << source; } - static void assertPointerCoords(const PointerCoords& coords, - float x, float y, float pressure, float size, - float touchMajor, float touchMinor, float toolMajor, float toolMinor, - float orientation, float distance) { - ASSERT_NEAR(x, coords.getAxisValue(AMOTION_EVENT_AXIS_X), 1); - ASSERT_NEAR(y, coords.getAxisValue(AMOTION_EVENT_AXIS_Y), 1); + static void assertPointerCoords(const PointerCoords& coords, float x, float y, float pressure, + float size, float touchMajor, float touchMinor, float toolMajor, + float toolMinor, float orientation, float distance, + float scaledAxisEpsilon = 1.f) { + ASSERT_NEAR(x, coords.getAxisValue(AMOTION_EVENT_AXIS_X), scaledAxisEpsilon); + ASSERT_NEAR(y, coords.getAxisValue(AMOTION_EVENT_AXIS_Y), scaledAxisEpsilon); ASSERT_NEAR(pressure, coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), EPSILON); ASSERT_NEAR(size, coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE), EPSILON); - ASSERT_NEAR(touchMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), 1); - ASSERT_NEAR(touchMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), 1); - ASSERT_NEAR(toolMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), 1); - ASSERT_NEAR(toolMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), 1); + ASSERT_NEAR(touchMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), + scaledAxisEpsilon); + ASSERT_NEAR(touchMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), + scaledAxisEpsilon); + ASSERT_NEAR(toolMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), + scaledAxisEpsilon); + ASSERT_NEAR(toolMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), + scaledAxisEpsilon); ASSERT_NEAR(orientation, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), EPSILON); ASSERT_NEAR(distance, coords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), EPSILON); } @@ -3822,6 +3826,12 @@ protected: setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation, uniqueId, NO_PORT, viewportType); } + + static void assertCursorPointerCoords(const PointerCoords& coords, float x, float y, + float pressure) { + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(coords, x, y, pressure, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, EPSILON)); + } }; const int32_t CursorInputMapperTest::TRACKBALL_MOVEMENT_THRESHOLD = 6; @@ -3836,10 +3846,10 @@ void CursorInputMapperTest::testMotionRotation(CursorInputMapper& mapper, int32_ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - float(rotatedX) / TRACKBALL_MOVEMENT_THRESHOLD, - float(rotatedY) / TRACKBALL_MOVEMENT_THRESHOLD, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(args.pointerCoords[0], + float(rotatedX) / TRACKBALL_MOVEMENT_THRESHOLD, + float(rotatedY) / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f)); } TEST_F(CursorInputMapperTest, WhenModeIsPointer_GetSources_ReturnsMouse) { @@ -3929,8 +3939,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat ASSERT_EQ(uint32_t(1), args.pointerCount); ASSERT_EQ(0, args.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 1.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); ASSERT_EQ(ARBITRARY_TIME, args.downTime); @@ -3948,8 +3957,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat ASSERT_EQ(uint32_t(1), args.pointerCount); ASSERT_EQ(0, args.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 1.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); ASSERT_EQ(ARBITRARY_TIME, args.downTime); @@ -3970,8 +3978,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat ASSERT_EQ(uint32_t(1), args.pointerCount); ASSERT_EQ(0, args.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); ASSERT_EQ(ARBITRARY_TIME, args.downTime); @@ -3989,8 +3996,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat ASSERT_EQ(uint32_t(1), args.pointerCount); ASSERT_EQ(0, args.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); ASSERT_EQ(ARBITRARY_TIME, args.downTime); @@ -4007,16 +4013,17 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], + 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, + 0.0f)); // Motion in Y but not X. process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, -2); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, + -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f)); } TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { @@ -4030,26 +4037,22 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 1.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 1.0f)); // Button release. process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_MOUSE, 0); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { @@ -4065,15 +4068,15 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], + 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, + -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], + 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, + -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f)); // Move X, Y a bit while pressed. process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 2); @@ -4081,22 +4084,20 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], + 2.0f / TRACKBALL_MOVEMENT_THRESHOLD, + 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f)); // Release Button. process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_MOUSE, 0); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) { @@ -4178,15 +4179,15 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f)); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_LEFT, 0); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); @@ -4194,22 +4195,22 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_RIGHT, 1); @@ -4221,16 +4222,16 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action); @@ -4238,8 +4239,8 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f)); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_RIGHT, 0); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); @@ -4247,15 +4248,15 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f)); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_MIDDLE, 0); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); @@ -4263,8 +4264,8 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_MIDDLE, 0); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); @@ -4272,15 +4273,15 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); // press BTN_BACK, release BTN_BACK process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_BACK, 1); @@ -4293,15 +4294,15 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_BACK, 0); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); @@ -4309,16 +4310,16 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); @@ -4334,15 +4335,15 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_SIDE, 0); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); @@ -4350,15 +4351,15 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); @@ -4375,15 +4376,15 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_FORWARD, 0); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); @@ -4391,15 +4392,15 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); @@ -4416,15 +4417,15 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_EXTRA, 0); process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); @@ -4432,15 +4433,15 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); + ASSERT_NO_FATAL_FAILURE( + assertCursorPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); @@ -8743,20 +8744,20 @@ protected: } }; -TEST_F(LightControllerTest, SingleLight) { - RawLightInfo infoSingle = {.id = 1, - .name = "Mono", - .maxBrightness = 255, - .flags = InputLightClass::BRIGHTNESS, - .path = ""}; - mFakeEventHub->addRawLightInfo(infoSingle.id, std::move(infoSingle)); +TEST_F(LightControllerTest, MonoLight) { + RawLightInfo infoMono = {.id = 1, + .name = "Mono", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS, + .path = ""}; + mFakeEventHub->addRawLightInfo(infoMono.id, std::move(infoMono)); PeripheralController& controller = addControllerAndConfigure<PeripheralController>(); InputDeviceInfo info; controller.populateDeviceInfo(&info); const auto& ids = info.getLightIds(); ASSERT_EQ(1UL, ids.size()); - ASSERT_EQ(InputDeviceLightType::SINGLE, info.getLightInfo(ids[0])->type); + ASSERT_EQ(InputDeviceLightType::MONO, info.getLightInfo(ids[0])->type); ASSERT_TRUE(controller.setLightColor(ids[0], LIGHT_BRIGHTNESS)); ASSERT_EQ(controller.getLightColor(ids[0]).value_or(-1), LIGHT_BRIGHTNESS); diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index f20bfe1b41..e669e4532b 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -188,6 +188,7 @@ filegroup { "SurfaceInterceptor.cpp", "SurfaceTracing.cpp", "TransactionCallbackInvoker.cpp", + "TunnelModeEnabledReporter.cpp", ], } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp index 2f2cc06c9b..297c0b2f7e 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp @@ -30,10 +30,11 @@ namespace android::compositionengine::impl::planner { Planner::Planner() - : mFlattener(base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), false)) { - // Implicitly, layer caching must also be enabled. - // E.g., setprop debug.sf.enable_layer_caching 1, or - // adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>] + // Implicitly, layer caching must also be enabled for the hole punch or + // predictor to have any effect. + // E.g., setprop debug.sf.enable_layer_caching 1, or + // adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>] + : mFlattener(base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), true)) { mPredictorEnabled = base::GetBoolProperty(std::string("debug.sf.enable_planner_prediction"), false); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7085eaf86a..881ee5b8f4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -23,7 +23,6 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "SurfaceFlinger.h" -#include "TraceUtils.h" #include <android-base/properties.h> #include <android/configuration.h> @@ -58,6 +57,7 @@ #include <gui/LayerMetadata.h> #include <gui/LayerState.h> #include <gui/Surface.h> +#include <gui/TraceUtils.h> #include <hidl/ServiceManagement.h> #include <layerproto/LayerProtoParser.h> #include <log/log.h> @@ -130,6 +130,7 @@ #include "SurfaceFlingerProperties.h" #include "SurfaceInterceptor.h" #include "TimeStats/TimeStats.h" +#include "TunnelModeEnabledReporter.h" #include "android-base/parseint.h" #include "android-base/stringprintf.h" #include "android-base/strings.h" @@ -1468,6 +1469,26 @@ status_t SurfaceFlinger::removeFpsListener(const sp<gui::IFpsListener>& listener return NO_ERROR; } +status_t SurfaceFlinger::addTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) { + if (!listener) { + return BAD_VALUE; + } + + mTunnelModeEnabledReporter->addListener(listener); + return NO_ERROR; +} + +status_t SurfaceFlinger::removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) { + if (!listener) { + return BAD_VALUE; + } + + mTunnelModeEnabledReporter->removeListener(listener); + return NO_ERROR; +} + status_t SurfaceFlinger::getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) const { if (!displayToken || !outSupport) { @@ -2191,6 +2212,10 @@ void SurfaceFlinger::postComposition() { if (mFpsReporter) { mFpsReporter->dispatchLayerFps(); } + + if (mTunnelModeEnabledReporter) { + mTunnelModeEnabledReporter->updateTunnelModeStatus(); + } hdrInfoListeners.reserve(mHdrLayerInfoListeners.size()); for (auto& [key, value] : mHdrLayerInfoListeners) { if (value && value->hasListeners()) { @@ -3067,6 +3092,7 @@ void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) { mRegionSamplingThread = new RegionSamplingThread(*this, RegionSamplingThread::EnvironmentTimingTunables()); mFpsReporter = new FpsReporter(*mFrameTimeline, *this); + mTunnelModeEnabledReporter = new TunnelModeEnabledReporter(*this); // Dispatch a mode change request for the primary display on scheduler // initialization, so that the EventThreads always contain a reference to a // prior configuration. @@ -5072,6 +5098,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: case GET_DISPLAYED_CONTENT_SAMPLE: + case ADD_TUNNEL_MODE_ENABLED_LISTENER: + case REMOVE_TUNNEL_MODE_ENABLED_LISTENER: case NOTIFY_POWER_BOOST: case SET_GLOBAL_SHADOW_SETTINGS: case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index cb8d312e9c..c3820053c1 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -90,6 +90,7 @@ namespace android { class Client; class EventThread; class FpsReporter; +class TunnelModeEnabledReporter; class HdrLayerInfoReporter; class HWComposer; struct SetInputWindowsListener; @@ -359,6 +360,7 @@ private: friend class BufferStateLayer; friend class Client; friend class FpsReporter; + friend class TunnelModeEnabledReporter; friend class Layer; friend class MonitoredProducer; friend class RefreshRateOverlay; @@ -673,6 +675,10 @@ private: status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override; status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) override; status_t removeFpsListener(const sp<gui::IFpsListener>& listener) override; + status_t addTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) override; + status_t removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) override; status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, ui::DisplayModeId displayModeId, bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, @@ -1368,6 +1374,7 @@ private: bool mLumaSampling = true; sp<RegionSamplingThread> mRegionSamplingThread; sp<FpsReporter> mFpsReporter; + sp<TunnelModeEnabledReporter> mTunnelModeEnabledReporter; ui::DisplayPrimaries mInternalDisplayPrimaries; const float mInternalDisplayDensity; diff --git a/services/surfaceflinger/TunnelModeEnabledReporter.cpp b/services/surfaceflinger/TunnelModeEnabledReporter.cpp new file mode 100644 index 0000000000..1b3ddf7a00 --- /dev/null +++ b/services/surfaceflinger/TunnelModeEnabledReporter.cpp @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#undef LOG_TAG +#define LOG_TAG "TunnelModeEnabledReporter" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include <algorithm> + +#include "Layer.h" +#include "SurfaceFlinger.h" +#include "TunnelModeEnabledReporter.h" + +namespace android { + +TunnelModeEnabledReporter::TunnelModeEnabledReporter(SurfaceFlinger& flinger) : mFlinger(flinger) {} + +void TunnelModeEnabledReporter::updateTunnelModeStatus() { + bool tunnelModeEnabled = false; + mFlinger.mCurrentState.traverse([&](Layer* layer) { + auto& currentState = layer->getCurrentState(); + if (currentState.sidebandStream != nullptr) { + tunnelModeEnabled = true; + return; + } + }); + dispatchTunnelModeEnabled(tunnelModeEnabled); +} + +void TunnelModeEnabledReporter::dispatchTunnelModeEnabled(bool tunnelModeEnabled) { + std::vector<sp<gui::ITunnelModeEnabledListener>> localListeners; + { + std::scoped_lock lock(mMutex); + if (mTunnelModeEnabled == tunnelModeEnabled) { + return; + } + mTunnelModeEnabled = tunnelModeEnabled; + + std::transform(mListeners.begin(), mListeners.end(), std::back_inserter(localListeners), + [](const std::pair<wp<IBinder>, sp<gui::ITunnelModeEnabledListener>>& + entry) { return entry.second; }); + } + + for (sp<gui::ITunnelModeEnabledListener>& listener : localListeners) { + listener->onTunnelModeEnabledChanged(tunnelModeEnabled); + } +} + +void TunnelModeEnabledReporter::binderDied(const wp<IBinder>& who) { + std::scoped_lock lock(mMutex); + mListeners.erase(who); +} + +void TunnelModeEnabledReporter::addListener(const sp<gui::ITunnelModeEnabledListener>& listener) { + sp<IBinder> asBinder = IInterface::asBinder(listener); + asBinder->linkToDeath(this); + bool tunnelModeEnabled = false; + { + std::scoped_lock lock(mMutex); + mListeners.emplace(wp<IBinder>(asBinder), listener); + tunnelModeEnabled = mTunnelModeEnabled; + } + listener->onTunnelModeEnabledChanged(tunnelModeEnabled); +} + +void TunnelModeEnabledReporter::removeListener( + const sp<gui::ITunnelModeEnabledListener>& listener) { + std::lock_guard lock(mMutex); + mListeners.erase(wp<IBinder>(IInterface::asBinder(listener))); +} + +} // namespace android diff --git a/services/surfaceflinger/TunnelModeEnabledReporter.h b/services/surfaceflinger/TunnelModeEnabledReporter.h new file mode 100644 index 0000000000..d55507a8e9 --- /dev/null +++ b/services/surfaceflinger/TunnelModeEnabledReporter.h @@ -0,0 +1,66 @@ +/* + * 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-base/thread_annotations.h> +#include <android/gui/ITunnelModeEnabledListener.h> +#include <binder/IBinder.h> + +#include <unordered_map> + +namespace android { + +class Layer; +class SurfaceFlinger; + +class TunnelModeEnabledReporter : public IBinder::DeathRecipient { +public: + TunnelModeEnabledReporter(SurfaceFlinger& flinger); + + // Checks if there is a tunnel mode enabled state change and if so, dispatches the updated + // tunnel mode enabled/disabled state to the registered listeners + // This method performs layer stack traversals, so mStateLock must be held when calling this + // method. + void updateTunnelModeStatus(); + + // Dispatches tunnelModeEnabled to all registered listeners + void dispatchTunnelModeEnabled(bool tunnelModeEnabled); + + // Override for IBinder::DeathRecipient + void binderDied(const wp<IBinder>&) override; + + // Registers a TunnelModeEnabled listener + void addListener(const sp<gui::ITunnelModeEnabledListener>& listener); + + // Deregisters a TunnelModeEnabled listener + void removeListener(const sp<gui::ITunnelModeEnabledListener>& listener); + +private: + mutable std::mutex mMutex; + struct WpHash { + size_t operator()(const wp<IBinder>& p) const { + return std::hash<IBinder*>()(p.unsafe_get()); + } + }; + + SurfaceFlinger& mFlinger; + std::unordered_map<wp<IBinder>, sp<gui::ITunnelModeEnabledListener>, WpHash> mListeners + GUARDED_BY(mMutex); + bool mTunnelModeEnabled GUARDED_BY(mMutex) = false; +}; + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index b33434e34d..1b25a3684e 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -86,6 +86,7 @@ cc_test { "TransactionApplicationTest.cpp", "TransactionFrameTracerTest.cpp", "TransactionSurfaceFrameTest.cpp", + "TunnelModeEnabledReporterTest.cpp", "StrongTypingTest.cpp", "VSyncDispatchTimerQueueTest.cpp", "VSyncDispatchRealtimeTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index d004b9d9eb..a551248dd6 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -276,6 +276,7 @@ public: static void setLayerSidebandStream(const sp<Layer>& layer, const sp<NativeHandle>& sidebandStream) { layer->mDrawingState.sidebandStream = sidebandStream; + layer->mCurrentState.sidebandStream = sidebandStream; layer->mSidebandStream = sidebandStream; layer->editCompositionState()->sidebandStream = sidebandStream; } diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp new file mode 100644 index 0000000000..d7d7ea77d6 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp @@ -0,0 +1,194 @@ +/* + * 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. + */ + +#undef LOG_TAG +#define LOG_TAG "TunnelModeEnabledReporterTest" + +#include <android/gui/BnTunnelModeEnabledListener.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <gui/LayerMetadata.h> + +#include "BufferStateLayer.h" +#include "TestableSurfaceFlinger.h" +#include "TunnelModeEnabledReporter.h" +#include "mock/DisplayHardware/MockComposer.h" +#include "mock/MockEventThread.h" + +namespace android { + +using testing::_; +using testing::Mock; +using testing::Return; + +using android::Hwc2::IComposer; +using android::Hwc2::IComposerClient; + +using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; + +constexpr int DEFAULT_SIDEBAND_STREAM = 51; + +struct TestableTunnelModeEnabledListener : public gui::BnTunnelModeEnabledListener { + TestableTunnelModeEnabledListener() {} + + bool mTunnelModeEnabled = false; + + binder::Status onTunnelModeEnabledChanged(bool tunnelModeEnabled) override { + mTunnelModeEnabled = tunnelModeEnabled; + return binder::Status::ok(); + } +}; + +class TunnelModeEnabledReporterTest : public testing::Test { +public: + TunnelModeEnabledReporterTest(); + ~TunnelModeEnabledReporterTest() override; + +protected: + static constexpr uint32_t WIDTH = 100; + static constexpr uint32_t HEIGHT = 100; + static constexpr uint32_t LAYER_FLAGS = 0; + + void setupScheduler(); + void setupComposer(uint32_t virtualDisplayCount); + sp<BufferStateLayer> createBufferStateLayer(LayerMetadata metadata); + + TestableSurfaceFlinger mFlinger; + Hwc2::mock::Composer* mComposer = nullptr; + sp<TestableTunnelModeEnabledListener> mTunnelModeEnabledListener = + new TestableTunnelModeEnabledListener(); + sp<TunnelModeEnabledReporter> mTunnelModeEnabledReporter = + new TunnelModeEnabledReporter(*(mFlinger.flinger())); +}; + +TunnelModeEnabledReporterTest::TunnelModeEnabledReporterTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + setupScheduler(); + mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>()); + mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(false); +} + +TunnelModeEnabledReporterTest::~TunnelModeEnabledReporterTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); + mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(false); + mTunnelModeEnabledReporter->removeListener(mTunnelModeEnabledListener); +} + +sp<BufferStateLayer> TunnelModeEnabledReporterTest::createBufferStateLayer( + LayerMetadata metadata = {}) { + sp<Client> client; + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", WIDTH, HEIGHT, + LAYER_FLAGS, metadata); + return new BufferStateLayer(args); +} + +void TunnelModeEnabledReporterTest::setupScheduler() { + auto eventThread = std::make_unique<mock::EventThread>(); + auto sfEventThread = std::make_unique<mock::EventThread>(); + + EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*eventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, + ResyncCallback()))); + + EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, + ResyncCallback()))); + + auto vsyncController = std::make_unique<mock::VsyncController>(); + auto vsyncTracker = std::make_unique<mock::VSyncTracker>(); + + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, currentPeriod()) + .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), + std::move(eventThread), std::move(sfEventThread)); +} + +namespace { + +TEST_F(TunnelModeEnabledReporterTest, callsAddedListeners) { + mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener); + + bool expectedTunnelModeEnabled = false; + mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(expectedTunnelModeEnabled); + EXPECT_EQ(expectedTunnelModeEnabled, mTunnelModeEnabledListener->mTunnelModeEnabled); + + expectedTunnelModeEnabled = true; + mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(expectedTunnelModeEnabled); + EXPECT_EQ(expectedTunnelModeEnabled, mTunnelModeEnabledListener->mTunnelModeEnabled); + + mTunnelModeEnabledReporter->removeListener(mTunnelModeEnabledListener); + + mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(false); + EXPECT_EQ(expectedTunnelModeEnabled, mTunnelModeEnabledListener->mTunnelModeEnabled); +} + +TEST_F(TunnelModeEnabledReporterTest, callsNewListenerImmediately) { + bool expectedTunnelModeEnabled = false; + mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(expectedTunnelModeEnabled); + + mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener); + EXPECT_EQ(expectedTunnelModeEnabled, mTunnelModeEnabledListener->mTunnelModeEnabled); +} + +TEST_F(TunnelModeEnabledReporterTest, callsNewListenerWithFreshInformation) { + sp<Layer> layer = createBufferStateLayer(); + sp<NativeHandle> stream = + NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM), + false); + mFlinger.setLayerSidebandStream(layer, stream); + mFlinger.mutableCurrentState().layersSortedByZ.add(layer); + mTunnelModeEnabledReporter->updateTunnelModeStatus(); + mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener); + EXPECT_EQ(true, mTunnelModeEnabledListener->mTunnelModeEnabled); + mTunnelModeEnabledReporter->removeListener(mTunnelModeEnabledListener); + + mFlinger.mutableCurrentState().layersSortedByZ.remove(layer); + mTunnelModeEnabledReporter->updateTunnelModeStatus(); + mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener); + EXPECT_EQ(false, mTunnelModeEnabledListener->mTunnelModeEnabled); +} + +TEST_F(TunnelModeEnabledReporterTest, layerWithSidebandStreamTriggersUpdate) { + mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener); + EXPECT_EQ(false, mTunnelModeEnabledListener->mTunnelModeEnabled); + + sp<Layer> simpleLayer = createBufferStateLayer(); + sp<Layer> layerWithSidebandStream = createBufferStateLayer(); + sp<NativeHandle> stream = + NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM), + false); + mFlinger.setLayerSidebandStream(layerWithSidebandStream, stream); + + mFlinger.mutableCurrentState().layersSortedByZ.add(simpleLayer); + mFlinger.mutableCurrentState().layersSortedByZ.add(layerWithSidebandStream); + mTunnelModeEnabledReporter->updateTunnelModeStatus(); + EXPECT_EQ(true, mTunnelModeEnabledListener->mTunnelModeEnabled); + + mFlinger.mutableCurrentState().layersSortedByZ.remove(layerWithSidebandStream); + mTunnelModeEnabledReporter->updateTunnelModeStatus(); + EXPECT_EQ(false, mTunnelModeEnabledListener->mTunnelModeEnabled); +} + +} // namespace +} // namespace android |