Merge "SkiaRE: Use RGB_888x for isOpaque" into sc-dev
diff --git a/aidl/gui/android/view/LayerMetadataKey.aidl b/aidl/gui/android/view/LayerMetadataKey.aidl
index a1d8ce5..d6ca3db 100644
--- a/aidl/gui/android/view/LayerMetadataKey.aidl
+++ b/aidl/gui/android/view/LayerMetadataKey.aidl
@@ -26,4 +26,5 @@
METADATA_ACCESSIBILITY_ID = 5,
METADATA_OWNER_PID = 6,
METADATA_DEQUEUE_TIME = 7,
+ METADATA_GAME_MODE = 8,
}
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 712adfa..1fec080 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -101,7 +101,7 @@
};
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 c605e67..445df9e 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -614,12 +614,6 @@
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 4fd0dc7..bade918 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -401,7 +401,7 @@
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 b99ca09..3100518 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 5d04ebe..196a41b 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -162,12 +162,6 @@
// 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/include/binder/ParcelRef.h b/libs/binder/include/binder/ParcelRef.h
deleted file mode 100644
index 497da2d..0000000
--- a/libs/binder/include/binder/ParcelRef.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-
-#include <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
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 0c3fbcd..5612d1d 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, 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 53721cf..71e18a9 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -824,6 +824,36 @@
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 @@
}
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/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp
index 634d8b7..189d51a 100644
--- a/libs/gui/LayerMetadata.cpp
+++ b/libs/gui/LayerMetadata.cpp
@@ -136,6 +136,8 @@
return StringPrintf("ownerPID%s%d", separator, getInt32(key, 0));
case view::LayerMetadataKey::METADATA_DEQUEUE_TIME:
return StringPrintf("dequeueTime%s%" PRId64, separator, *getInt64(key));
+ case view::LayerMetadataKey::METADATA_GAME_MODE:
+ return StringPrintf("gameMode%s%d", separator, getInt32(key, 0));
default:
return StringPrintf("%d%s%dbytes", key, separator,
static_cast<int>(mMap.at(key).size()));
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index d27d1ec..e117d11 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1268,8 +1268,11 @@
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 aa93808..371454a 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -65,12 +65,12 @@
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 @@
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 @@
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/gui/aidl/android/gui/ITunnelModeEnabledListener.aidl b/libs/gui/aidl/android/gui/ITunnelModeEnabledListener.aidl
new file mode 100644
index 0000000..2a89cca
--- /dev/null
+++ b/libs/gui/aidl/android/gui/ITunnelModeEnabledListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+/** @hide */
+oneway interface ITunnelModeEnabledListener {
+
+ /**
+ * 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 cb04689..439d90a 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 @@
*/
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 @@
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/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h
index 41982c2..de14b3d 100644
--- a/libs/gui/include/gui/LayerMetadata.h
+++ b/libs/gui/include/gui/LayerMetadata.h
@@ -29,7 +29,8 @@
METADATA_MOUSE_CURSOR = 4,
METADATA_ACCESSIBILITY_ID = 5,
METADATA_OWNER_PID = 6,
- METADATA_DEQUEUE_TIME = 7
+ METADATA_DEQUEUE_TIME = 7,
+ METADATA_GAME_MODE = 8
};
struct LayerMetadata : public Parcelable {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0940e9d..2582882 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -50,6 +50,7 @@
class ISurfaceComposerClient;
class IGraphicBufferProducer;
class IRegionSamplingListener;
+class ITunnelModeEnabledListener;
class Region;
struct SurfaceControlStats {
@@ -610,6 +611,10 @@
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
similarity index 89%
rename from services/surfaceflinger/TraceUtils.h
rename to libs/gui/include/gui/TraceUtils.h
index 90a34a5..b9ec14a 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 50bd742..fa1071a 100644
--- a/libs/gui/include/private/gui/ComposerService.h
+++ b/libs/gui/include/private/gui/ComposerService.h
@@ -45,13 +45,12 @@
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 ea8c295..b8d34c3 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -845,6 +845,16 @@
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 649a140..70ed438 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -39,6 +39,60 @@
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::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 @@
}
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);
+
+ 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];
}
- // 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;
- }
- 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 @@
}
}
-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/permission/Android.bp b/libs/permission/Android.bp
index 3243a6b..0eeca54 100644
--- a/libs/permission/Android.bp
+++ b/libs/permission/Android.bp
@@ -11,19 +11,24 @@
name: "framework-permission-aidl",
unstable: true,
local_include_dir: "aidl",
- backend: {
- ndk: {
- enabled: false
- }
- },
+ host_supported: true,
+ vendor_available: true,
+ double_loadable: true,
srcs: [
"aidl/android/content/AttributionSourceState.aidl",
"aidl/android/permission/IPermissionChecker.aidl",
],
}
-cc_library_shared {
+cc_library {
name: "libpermission",
+ host_supported: true,
+ double_loadable: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
cflags: [
"-Wall",
"-Wextra",
@@ -45,5 +50,7 @@
static_libs: [
"framework-permission-aidl-cpp",
],
- export_static_lib_headers: ["framework-permission-aidl-cpp"],
+ export_static_lib_headers: [
+ "framework-permission-aidl-cpp"
+ ],
}
diff --git a/libs/permission/aidl/android/content/AttributionSourceState.aidl b/libs/permission/aidl/android/content/AttributionSourceState.aidl
index b6e54bf..ed1b37d 100644
--- a/libs/permission/aidl/android/content/AttributionSourceState.aidl
+++ b/libs/permission/aidl/android/content/AttributionSourceState.aidl
@@ -23,8 +23,10 @@
* {@hide}
*/
parcelable AttributionSourceState {
+ /** The PID that is accessing the permission protected data. */
+ int pid = -1;
/** The UID that is accessing the permission protected data. */
- int uid;
+ int uid = -1;
/** The package that is accessing the permission protected data. */
@nullable @utf8InCpp String packageName;
/** The attribution tag of the app accessing the permission protected data. */
@@ -36,5 +38,5 @@
/** The next app to receive the permission protected data. */
// TODO: We use an array as a workaround - the C++ backend doesn't
// support referring to the parcelable as it expects ctor/dtor
- @nullable AttributionSourceState[] next;
+ AttributionSourceState[] next;
}
diff --git a/libs/permission/aidl/android/permission/IPermissionChecker.aidl b/libs/permission/aidl/android/permission/IPermissionChecker.aidl
index 1f0e32d..d3a331e 100644
--- a/libs/permission/aidl/android/permission/IPermissionChecker.aidl
+++ b/libs/permission/aidl/android/permission/IPermissionChecker.aidl
@@ -28,9 +28,10 @@
int checkPermission(String permission, in AttributionSourceState attributionSource,
@nullable String message, boolean forDataDelivery, boolean startDataDelivery,
- boolean fromDatasource);
+ boolean fromDatasource, int attributedOp);
- void finishDataDelivery(String op, in AttributionSourceState attributionSource);
+ void finishDataDelivery(int op, in AttributionSourceState attributionSource,
+ boolean fromDatasource);
int checkOp(int op, in AttributionSourceState attributionSource,
String message, boolean forDataDelivery, boolean startDataDelivery);
diff --git a/libs/permission/android/permission/PermissionChecker.cpp b/libs/permission/android/permission/PermissionChecker.cpp
index a8083ee..008afad 100644
--- a/libs/permission/android/permission/PermissionChecker.cpp
+++ b/libs/permission/android/permission/PermissionChecker.cpp
@@ -29,7 +29,7 @@
#endif
#define LOG_TAG "PermissionChecker"
-namespace android {
+namespace android::permission {
using android::content::AttributionSourceState;
@@ -37,7 +37,7 @@
{
}
-sp<IPermissionChecker> PermissionChecker::getService()
+sp<android::permission::IPermissionChecker> PermissionChecker::getService()
{
static String16 permission_checker("permission_checker");
@@ -59,56 +59,66 @@
sleep(1);
} else {
mService = interface_cast<IPermissionChecker>(binder);
+ break;
}
}
return mService;
}
-PermissionChecker::PermissionResult
- PermissionChecker::checkPermissionForDataDeliveryFromDatasource(
- const String16& permission, AttributionSourceState& attributionSource,
- const String16& message)
+PermissionChecker::PermissionResult PermissionChecker::checkPermissionForDataDeliveryFromDatasource(
+ const String16& permission, const AttributionSourceState& attributionSource,
+ const String16& message, int32_t attributedOpCode)
{
- return static_cast<PermissionResult>(checkPermission(permission, attributionSource, message,
- /*forDataDelivery*/ true, /*startDataDelivery*/ false,/*fromDatasource*/ true));
+ return checkPermission(permission, attributionSource, message, /*forDataDelivery*/ true,
+ /*startDataDelivery*/ false,/*fromDatasource*/ true, attributedOpCode);
}
PermissionChecker::PermissionResult
- PermissionChecker::checkPermissionForStartDataDeliveryFromDatasource(
- const String16& permission, AttributionSourceState& attributionSource,
- const String16& message)
+ PermissionChecker::checkPermissionForStartDataDeliveryFromDatasource(
+ const String16& permission, const AttributionSourceState& attributionSource,
+ const String16& message, int32_t attributedOpCode)
{
- return static_cast<PermissionResult>(checkPermission(permission, attributionSource, message,
- /*forDataDelivery*/ true, /*startDataDelivery*/ true, /*fromDatasource*/ true));
+ return checkPermission(permission, attributionSource, message, /*forDataDelivery*/ true,
+ /*startDataDelivery*/ true, /*fromDatasource*/ true, attributedOpCode);
}
-void PermissionChecker::finishDataDelivery(const String16& op,
- AttributionSourceState& attributionSource)
+PermissionChecker::PermissionResult PermissionChecker::checkPermissionForPreflightFromDatasource(
+ const String16& permission, const AttributionSourceState& attributionSource,
+ const String16& message, int32_t attributedOpCode)
+{
+ return checkPermission(permission, attributionSource, message, /*forDataDelivery*/ false,
+ /*startDataDelivery*/ false, /*fromDatasource*/ true, attributedOpCode);
+}
+
+void PermissionChecker::finishDataDeliveryFromDatasource(int32_t op,
+ const AttributionSourceState& attributionSource)
{
sp<IPermissionChecker> service = getService();
if (service != nullptr) {
- binder::Status status = service->finishDataDelivery(op, attributionSource);
+ binder::Status status = service->finishDataDelivery(op, attributionSource,
+ /*fromDatasource*/ true);
if (!status.isOk()) {
ALOGE("finishDataDelivery failed: %s", status.exceptionMessage().c_str());
}
}
}
-int32_t PermissionChecker::checkPermission(const String16& permission,
- AttributionSourceState& attributionSource, const String16& message,
- bool forDataDelivery, bool startDataDelivery, bool fromDatasource)
+PermissionChecker::PermissionResult PermissionChecker::checkPermission(const String16& permission,
+ const AttributionSourceState& attributionSource, const String16& message,
+ bool forDataDelivery, bool startDataDelivery, bool fromDatasource,
+ int32_t attributedOpCode)
{
sp<IPermissionChecker> service = getService();
if (service != nullptr) {
int32_t result;
binder::Status status = service->checkPermission(permission, attributionSource, message,
- forDataDelivery, startDataDelivery, fromDatasource, &result);
+ forDataDelivery, startDataDelivery, fromDatasource, attributedOpCode, &result);
if (status.isOk()) {
- return result;
+ return static_cast<PermissionResult>(result);
}
ALOGE("checkPermission failed: %s", status.exceptionMessage().c_str());
}
- return PERMISSION_DENIED;
+ return PERMISSION_HARD_DENIED;
}
-} // namespace android
+} // namespace android::permission
diff --git a/libs/permission/include/android/permission/PermissionChecker.h b/libs/permission/include/android/permission/PermissionChecker.h
index 20ab51f..308d794 100644
--- a/libs/permission/include/android/permission/PermissionChecker.h
+++ b/libs/permission/include/android/permission/PermissionChecker.h
@@ -30,6 +30,8 @@
// ---------------------------------------------------------------------------
namespace android {
+namespace permission {
+
using android::content::AttributionSourceState;
using android::permission::IPermissionChecker;
@@ -71,7 +73,8 @@
* Checks whether a given data access chain described by the given attribution source
* has a given permission and whether the app op that corresponds to this permission
* is allowed. Call this method if you are the datasource which would not blame you for
- * access to the data since you are the data. Note that the attribution source chain
+ * access to the data since you are the data. Use this API if you are the datasource of
+ * the protected state.
*
* NOTE: The attribution source should be for yourself with its next attribution
* source being the app that would receive the data from you.
@@ -82,18 +85,49 @@
* @param permission The permission to check.
* @param attributionSource The attribution chain to check.
* @param message A message describing the reason the permission was checked.
+ * @param attributedOpCode The op code towards which to blame the access. If this
+ * is a valid app op the op corresponding to the checked permission (if such)
+ * would only be checked to ensure it is allowed and if that succeeds the
+ * noting would be against the attributed op.
* @return The permission check result which is either PERMISSION_GRANTED,
* or PERMISSION_SOFT_DENIED or PERMISSION_HARD_DENIED.
*/
PermissionChecker::PermissionResult checkPermissionForDataDeliveryFromDatasource(
- const String16& permission, AttributionSourceState& attributionSource,
- const String16& message);
+ const String16& permission, const AttributionSourceState& attributionSource,
+ const String16& message, int32_t attributedOpCode);
+
+ /**
+ * Checks whether a given data access chain described by the given attribution source
+ * has a given permission and whether the app op that corresponds to this permission
+ * is allowed. The app ops are not noted/started.
+ *
+ * NOTE: The attribution source should be for yourself with its next attribution
+ * source being the app that would receive the data from you.
+ *
+ * NOTE: Use this method only for permission checks at the preflight point where you
+ * will not deliver the permission protected data to clients but schedule permission
+ * data delivery, apps register listeners, etc.
+ *
+ * @param permission The permission to check.
+ * @param attributionSource The attribution chain to check.
+ * @param message A message describing the reason the permission was checked.
+ * @param attributedOpCode The op code towards which to blame the access. If this
+ * is a valid app op the op corresponding to the checked permission (if such)
+ * would only be checked to ensure it is allowed and if that succeeds the
+ * starting would be against the attributed op.
+ * @return The permission check result which is either PERMISSION_GRANTED,
+ * or PERMISSION_SOFT_DENIED or PERMISSION_HARD_DENIED.
+ */
+ PermissionResult checkPermissionForPreflightFromDatasource(
+ const String16& permission, const AttributionSourceState& attributionSource,
+ const String16& message, int32_t attributedOpCode);
/**
* Checks whether a given data access chain described by the given attribution source
* has a given permission and whether the app op that corresponds to this permission
* is allowed. The app ops are also marked as started. This is useful for long running
- * permissions like camera and microphone.
+ * permissions like camera and microphone. Use this API if you are the datasource of
+ * the protected state.
*
* NOTE: The attribution source should be for yourself with its next attribution
* source being the app that would receive the data from you.
@@ -104,32 +138,45 @@
* @param permission The permission to check.
* @param attributionSource The attribution chain to check.
* @param message A message describing the reason the permission was checked.
+ * @param attributedOpCode The op code towards which to blame the access. If this
+ * is a valid app op the op corresponding to the checked permission (if such)
+ * would only be checked to ensure it is allowed and if that succeeds the
+ * starting would be against the attributed op.
* @return The permission check result which is either PERMISSION_GRANTED,
* or PERMISSION_SOFT_DENIED or PERMISSION_HARD_DENIED.
*/
PermissionResult checkPermissionForStartDataDeliveryFromDatasource(
- const String16& permission, AttributionSourceState& attributionSource,
- const String16& message);
+ const String16& permission, const AttributionSourceState& attributionSource,
+ const String16& message, int32_t attributedOpCode);
/**
* Finishes an ongoing op for data access chain described by the given
- * attribution source.
+ * attribution source. Use this API if you are the datasource of the protected
+ * state. Use this API if you are the datasource of the protected state.
+ *
+ * NOTE: The attribution source should be for yourself with its next attribution
+ * source being the app that would receive the data from you.
*
* @param op The op to finish.
* @param attributionSource The attribution chain for which to finish data delivery.
+ * @param attributedOpCode The op code towards which to blame the access. If this
+ * is a valid app op it is the op that would be finished.
*/
- void finishDataDelivery(const String16& op, AttributionSourceState& attributionSource);
+ void finishDataDeliveryFromDatasource(int32_t op,
+ const AttributionSourceState& attributionSource);
private:
Mutex mLock;
sp<IPermissionChecker> mService;
sp<IPermissionChecker> getService();
- int32_t checkPermission(const String16& permission, AttributionSourceState& attributionSource,
+ PermissionResult checkPermission(const String16& permission,
+ const AttributionSourceState& attributionSource,
const String16& message, bool forDataDelivery, bool startDataDelivery,
- bool fromDatasource);
+ bool fromDatasource, int32_t attributedOpCode);
};
+} // namespace permission
} // namespace android
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index ddaa7c7..d1bbcc5 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -43,6 +43,11 @@
*/
#define PROPERTY_DEBUG_RENDERENGINE_CAPTURE_SKIA_MS "debug.renderengine.capture_skia_ms"
+/**
+ * Set to the most recently saved file once the capture is finished.
+ */
+#define PROPERTY_DEBUG_RENDERENGINE_CAPTURE_FILENAME "debug.renderengine.capture_filename"
+
struct ANativeWindowBuffer;
namespace android {
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index 77e01f4..61c297c 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -37,6 +37,10 @@
0.f, 0.7f, 0.f, 0.f,
0.f, 0.f, 1.f, 0.f,
67.3f, 52.2f, 0.f, 1.f);
+const auto kScaleAsymmetric = mat4(0.8f, 0.f, 0.f, 0.f,
+ 0.f, 1.1f, 0.f, 0.f,
+ 0.f, 0.f, 1.f, 0.f,
+ 0.f, 0.f, 0.f, 1.f);
// clang-format on
// When setting layer.sourceDataspace, whether it matches the destination or not determines whether
// a color correction effect is added to the shader.
@@ -77,12 +81,7 @@
// This matrix, which has different scales for x and y, will
// generate the slower (more general case) version, which has variants for translucent
// casters and rounded rects.
- // clang-format off
- layer.geometry.positionTransform = mat4(0.7f, 0.f, 0.f, 0.f,
- 0.f, 0.8f, 0.f, 0.f,
- 0.f, 0.f, 1.f, 0.f,
- 0.f, 0.f, 0.f, 1.f);
- // clang-format on
+ layer.geometry.positionTransform = kScaleAsymmetric;
for (auto translucent : {false, true}) {
layer.shadow.casterIsTranslucent = translucent;
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
@@ -150,7 +149,6 @@
PixelSource{
.solidColor = half3(0.1f, 0.2f, 0.3f),
},
- .alpha = 1,
};
auto layers = std::vector<const LayerSettings*>{&layer};
@@ -186,23 +184,26 @@
// The unique feature of these layers is that the boundary is slightly smaller than the rounded
// rect crop, so the rounded edges intersect that boundary and require a different clipping method.
+// For buffers, this is done with a stage that computes coverage and it will differ for round and
+// elliptical corners.
static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
const std::shared_ptr<ExternalTexture>& dstTexture,
const std::shared_ptr<ExternalTexture>& srcTexture) {
const Rect& displayRect = display.physicalDisplay;
FloatRect rect(0, 0, displayRect.width(), displayRect.height() - 20); // boundary is smaller
- // clang-format off
- const auto symmetric = mat4(0.9f, 0.f, 0.f, 0.f,
- 0.f, 0.9f, 0.f, 0.f,
- 0.f, 0.f, 1.f, 0.f,
- 8.8f, 8.1f, 0.f, 1.f);
- const auto asymmetric = mat4(0.9f, 0.f, 0.f, 0.f,
- 0.f, 0.7f, 0.f, 0.f,
- 0.f, 0.f, 1.f, 0.f,
- 8.8f, 8.1f, 0.f, 1.f);
+ PixelSource bufferSource{.buffer = Buffer{
+ .buffer = srcTexture,
+ .isOpaque = 0,
+ .maxLuminanceNits = 1000.f,
+ }};
+ PixelSource bufferOpaque{.buffer = Buffer{
+ .buffer = srcTexture,
+ .isOpaque = 1,
+ .maxLuminanceNits = 1000.f,
+ }};
+ PixelSource colorSource{.solidColor = half3(0.1f, 0.2f, 0.3f)};
- // clang-format on
LayerSettings layer{
.geometry =
Geometry{
@@ -211,23 +212,24 @@
.roundedCornersCrop =
FloatRect(0, 0, displayRect.width(), displayRect.height()),
},
- .source = PixelSource{.buffer =
- Buffer{
- .buffer = srcTexture,
- .isOpaque = 0,
- .maxLuminanceNits = 1000.f,
- }},
- .sourceDataspace = kOtherDataSpace,
};
auto layers = std::vector<const LayerSettings*>{&layer};
- for (auto transform : {symmetric, asymmetric}) {
- layer.geometry.positionTransform = transform;
- // In real use, I saw alpha of 1.0 and 0.999, probably a mistake, but cache both shaders.
- for (float alpha : {0.5f, 1.f}) {
- layer.alpha = alpha,
- renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) {
+ layer.source = pixelSource;
+ for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
+ layer.sourceDataspace = dataspace;
+ // Produce a CircularRRect clip and an EllipticalRRect clip
+ for (auto transform : {kScaleAndTranslate, kScaleAsymmetric}) {
+ layer.geometry.positionTransform = transform;
+ // In real use, I saw alpha of 1.0 and 0.999, probably a mistake, but cache both
+ // shaders.
+ for (float alpha : {0.5f, 1.f}) {
+ layer.alpha = alpha,
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
+ base::unique_fd(), nullptr);
+ }
+ }
}
}
}
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 3270df1..2d80c46 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -725,6 +725,14 @@
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 @@
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 @@
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 @@
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
@@ -1185,8 +1191,15 @@
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 4265c08..97d3b72 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -90,7 +90,7 @@
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/libs/renderengine/skia/debug/SkiaCapture.cpp b/libs/renderengine/skia/debug/SkiaCapture.cpp
index 40f5cf2..856fff4 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.cpp
+++ b/libs/renderengine/skia/debug/SkiaCapture.cpp
@@ -34,7 +34,7 @@
namespace skia {
// The root of the filename to write a recorded SKP to. In order for this file to
-// be written to /data/user/, user must run 'adb shell setenforce 0' in the device.
+// be written to /data/user/, user must run 'adb shell setenforce 0' on the device.
static const std::string CAPTURED_FILENAME_BASE = "/data/user/re_skiacapture";
SkiaCapture::~SkiaCapture() {
@@ -152,11 +152,12 @@
// a smart pointer makes the lambda non-copyable. The lambda is only called
// once, so this is safe.
SkFILEWStream* stream = mOpenMultiPicStream.release();
- CommonPool::post([doc = std::move(mMultiPic), stream] {
+ CommonPool::post([doc = std::move(mMultiPic), stream, name = std::move(mCaptureFile)] {
ALOGD("Finalizing multi frame SKP");
doc->close();
delete stream;
- ALOGD("Multi frame SKP complete.");
+ ALOGD("Multi frame SKP saved to %s.", name.c_str());
+ base::SetProperty(PROPERTY_DEBUG_RENDERENGINE_CAPTURE_FILENAME, name);
});
mCaptureRunning = false;
}
@@ -164,12 +165,14 @@
bool SkiaCapture::setupMultiFrameCapture() {
ATRACE_CALL();
ALOGD("Set up multi-frame capture, ms = %llu", mTimerInterval.count());
+ base::SetProperty(PROPERTY_DEBUG_RENDERENGINE_CAPTURE_FILENAME, "");
+ const std::scoped_lock lock(mMutex);
- std::string captureFile;
// Attach a timestamp to the file.
- base::StringAppendF(&captureFile, "%s_%lld.mskp", CAPTURED_FILENAME_BASE.c_str(),
+ mCaptureFile.clear();
+ base::StringAppendF(&mCaptureFile, "%s_%lld.mskp", CAPTURED_FILENAME_BASE.c_str(),
std::chrono::steady_clock::now().time_since_epoch().count());
- auto stream = std::make_unique<SkFILEWStream>(captureFile.c_str());
+ auto stream = std::make_unique<SkFILEWStream>(mCaptureFile.c_str());
// We own this stream and need to hold it until close() finishes.
if (stream->isValid()) {
mOpenMultiPicStream = std::move(stream);
@@ -194,7 +197,7 @@
mCaptureRunning = true;
return true;
} else {
- ALOGE("Could not open \"%s\" for writing.", captureFile.c_str());
+ ALOGE("Could not open \"%s\" for writing.", mCaptureFile.c_str());
return false;
}
}
diff --git a/libs/renderengine/skia/debug/SkiaCapture.h b/libs/renderengine/skia/debug/SkiaCapture.h
index 5e18e60..f194629 100644
--- a/libs/renderengine/skia/debug/SkiaCapture.h
+++ b/libs/renderengine/skia/debug/SkiaCapture.h
@@ -85,6 +85,8 @@
// Mutex to ensure that a frame in progress when the timer fires is allowed to run to
// completion before we write the file to disk.
std::mutex mMutex;
+
+ std::string mCaptureFile;
};
} // namespace skia
diff --git a/libs/renderengine/skia/debug/record.sh b/libs/renderengine/skia/debug/record.sh
index 25c8cef..e99b7ae 100755
--- a/libs/renderengine/skia/debug/record.sh
+++ b/libs/renderengine/skia/debug/record.sh
@@ -16,14 +16,22 @@
# first time use requires these changes
adb root
adb shell setenforce 0
- adb shell setprop debug.renderengine.backend "skiagl"
+ adb shell setprop debug.renderengine.backend "skiaglthreaded"
adb shell stop
adb shell start
exit 1;
fi
-# name of the newest file in /data/user/ before starting
-oldname=$(adb shell ls -cr /data/user/ | head -n 1)
+check_permission() {
+ adb shell getenforce
+}
+
+mode=$(check_permission)
+
+if [ "$mode" != "Permissive" ]; then
+ echo "Cannot write to disk from RenderEngine. run 'record.sh rootandsetup'"
+ exit 5
+fi
# record frames for some number of milliseconds.
adb shell setprop debug.renderengine.capture_skia_ms $1
@@ -38,26 +46,6 @@
# the process it is recording.
# /data/user/re_skiacapture_56204430551705.mskp
-# list the files here from newest to oldest, keep only the name of the newest.
-name=$(adb shell ls -cr /data/user/ | head -n 1)
-remote_path=/data/user/$name
-
-if [[ $oldname = $name ]]; then
- echo "No new file written, probably no RenderEngine activity during recording period."
- exit 1
-fi
-
-# return the size of a file in bytes
-adb_filesize() {
- adb shell "wc -c \"$1\"" 2> /dev/null | awk '{print $1}'
-}
-
-mskp_size=$(adb_filesize "/data/user/$name")
-if [[ $mskp_size = "0" ]]; then
- echo "File opened, but remains empty after recording period + wait. Either there was no RenderEngine activity during recording period, or recording process is still working. Check /data/user/$name manually later."
- exit 1
-fi
-
spin() {
case "$spin" in
1) printf '\b|';;
@@ -69,38 +57,28 @@
sleep $1
}
-printf "MSKP captured, Waiting for file serialization to finish.\n"
+local_path=~/Downloads/
-local_path=~/Downloads/$name
+get_filename() {
+ adb shell getprop debug.renderengine.capture_filename
+}
-# wait for the file size to stop changing
-
-timeout=$(( $(date +%s) + 300))
-last_size='0' # output of last size check command
-unstable=true # false once the file size stops changing
-counter=0 # used to perform size check only 1/sec though we update spinner 20/sec
-# loop until the file size is unchanged for 1 second.
-while [ $unstable != 0 ] ; do
+remote_path=""
+counter=0 # used to check only 1/sec though we update spinner 20/sec
+while [ -z $remote_path ] ; do
spin 0.05
counter=$(( $counter+1 ))
if ! (( $counter % 20)) ; then
- new_size=$(adb_filesize "$remote_path")
- unstable=$(($new_size != $last_size))
- last_size=$new_size
- fi
- if [ $(date +%s) -gt $timeout ] ; then
- printf '\bTimed out.\n'
- exit 3
+ remote_path=$(get_filename)
fi
done
printf '\b'
-printf "MSKP file serialized: %s\n" $(echo $last_size | numfmt --to=iec)
+printf "MSKP file serialized to: $remote_path\n"
-adb pull "$remote_path" "$local_path"
-if ! [ -f "$local_path" ] ; then
- printf "something went wrong with `adb pull`."
- exit 4
-fi
+adb_pull_cmd="adb pull $remote_path $local_path"
+echo $adb_pull_cmd
+$adb_pull_cmd
+
adb shell rm "$remote_path"
-printf 'SKP saved to %s\n\n' "$local_path"
\ No newline at end of file
+printf 'SKP saved to %s\n\n' "$local_path"
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 91d2d58..3f958ba 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -128,8 +128,9 @@
}
// Ensure that layerCount is valid.
- if (layerCount < 1)
+ if (layerCount < 1) {
layerCount = 1;
+ }
// TODO(b/72323293, b/72703005): Remove these invalid bits from callers
usage &= ~static_cast<uint64_t>((1 << 10) | (1 << 13));
@@ -140,7 +141,7 @@
ALOGE("Failed to allocate (%u x %u) layerCount %u format %d "
"usage %" PRIx64 ": %d",
width, height, layerCount, format, usage, error);
- return NO_MEMORY;
+ return error;
}
if (!importBuffer) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 790bd09..cf433c0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -89,6 +89,14 @@
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(
@@ -3885,12 +3893,6 @@
args->xCursorPosition, args->yCursorPosition,
args->downTime, args->pointerCount,
args->pointerProperties, args->pointerCoords, 0, 0);
- if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
- IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER &&
- !mInputFilterEnabled) {
- const bool isDown = args->action == AMOTION_EVENT_ACTION_DOWN;
- mLatencyTracker.trackListener(args->id, isDown, args->eventTime, args->readTime);
- }
needWake = enqueueInboundEventLocked(std::move(newEntry));
mLock.unlock();
@@ -4491,6 +4493,13 @@
// 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 +4548,25 @@
}
}
+ 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 1a40d06..16251ee 100644
--- a/services/inputflinger/reader/controller/PeripheralController.cpp
+++ b/services/inputflinger/reader/controller/PeripheralController.cpp
@@ -104,7 +104,7 @@
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 @@
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 @@
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 @@
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 @@
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 ff3607f..b1bc8c7 100644
--- a/services/inputflinger/reader/controller/PeripheralController.h
+++ b/services/inputflinger/reader/controller/PeripheralController.h
@@ -78,10 +78,10 @@
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 d6bd823..437902a 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -188,6 +188,8 @@
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 @@
config->getDisplayViewportByType(ViewportType::INTERNAL);
if (internalViewport) {
mOrientation = getInverseRotation(internalViewport->orientation);
+ mDisplayWidth = internalViewport->deviceWidth;
+ mDisplayHeight = internalViewport->deviceHeight;
}
}
} else {
@@ -360,13 +364,19 @@
}
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 9a8ca01..88e947f 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -105,6 +105,8 @@
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 1843b03..da0fea4 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -68,6 +68,29 @@
*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 fb65484..6050238 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 @@
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 @@
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 @@
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 @@
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 5eaca71..7a11ca7 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -2768,18 +2768,22 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
};
-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/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index 73a6db5..560834f 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -17,6 +17,7 @@
#include "SensorInterface.h"
#include "SensorDevice.h"
#include "SensorFusion.h"
+#include "SensorService.h"
#include <stdint.h>
#include <sys/types.h>
@@ -85,4 +86,35 @@
}
// ---------------------------------------------------------------------------
+
+ProximitySensor::ProximitySensor(const sensor_t& sensor, SensorService& service)
+ : HardwareSensor(sensor), mSensorService(service) {
+}
+
+status_t ProximitySensor::activate(void* ident, bool enabled) {
+ bool wasActive = mActive;
+ status_t status = HardwareSensor::activate(ident, enabled);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ mActive = enabled;
+ if (wasActive != enabled) {
+ mSensorService.onProximityActiveLocked(enabled);
+ }
+ return NO_ERROR;
+}
+
+void ProximitySensor::willDisableAllSensors() {
+ if (mSensorDevice.isSensorActive(mSensor.getHandle())) {
+ mSensorService.onProximityActiveLocked(false);
+ }
+}
+
+void ProximitySensor::didEnableAllSensors() {
+ if (mSensorDevice.isSensorActive(mSensor.getHandle())) {
+ mSensorService.onProximityActiveLocked(true);
+ }
+}
+
+// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index b5375cb..ea181c9 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -26,6 +26,7 @@
// ---------------------------------------------------------------------------
class SensorDevice;
class SensorFusion;
+class SensorService;
class SensorInterface : public VirtualLightRefBase {
public:
@@ -43,6 +44,9 @@
virtual const Sensor& getSensor() const = 0;
virtual bool isVirtual() const = 0;
virtual void autoDisable(void* /*ident*/, int /*handle*/) = 0;
+
+ virtual void willDisableAllSensors() = 0;
+ virtual void didEnableAllSensors() = 0;
};
class BaseSensor : public SensorInterface {
@@ -65,6 +69,9 @@
virtual const Sensor& getSensor() const override { return mSensor; }
virtual void autoDisable(void* /*ident*/, int /*handle*/) override { }
+
+ virtual void willDisableAllSensors() override { }
+ virtual void didEnableAllSensors() override { }
protected:
SensorDevice& mSensorDevice;
Sensor mSensor;
@@ -100,6 +107,20 @@
SensorFusion& mSensorFusion;
};
+// ---------------------------------------------------------------------------
+
+class ProximitySensor : public HardwareSensor {
+public:
+ explicit ProximitySensor(const sensor_t& sensor, SensorService& service);
+
+ status_t activate(void* ident, bool enabled) override;
+
+ void willDisableAllSensors() override;
+ void didEnableAllSensors() override;
+private:
+ SensorService& mSensorService;
+ bool mActive;
+};
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SensorList.h b/services/sensorservice/SensorList.h
index 617ceef..049ae7c 100644
--- a/services/sensorservice/SensorList.h
+++ b/services/sensorservice/SensorList.h
@@ -36,6 +36,15 @@
class SensorList : public Dumpable {
public:
+ struct Entry {
+ sp<SensorInterface> si;
+ const bool isForDebug;
+ const bool isVirtual;
+ Entry(SensorInterface* si_, bool debug_, bool virtual_) :
+ si(si_), isForDebug(debug_), isVirtual(virtual_) {
+ }
+ };
+
// After SensorInterface * is added into SensorList, it can be assumed that SensorList own the
// object it pointed to and the object should not be released elsewhere.
bool add(int handle, SensorInterface* si, bool isForDebug = false, bool isVirtual = false);
@@ -69,25 +78,6 @@
template <typename TF>
void forEachSensor(const TF& f) const;
- const Sensor& getNonSensor() const { return mNonSensor;}
-
- // Dumpable interface
- virtual std::string dump() const override;
- virtual void dump(util::ProtoOutputStream* proto) const override;
-
- virtual ~SensorList();
-private:
- struct Entry {
- sp<SensorInterface> si;
- const bool isForDebug;
- const bool isVirtual;
- Entry(SensorInterface* si_, bool debug_, bool virtual_) :
- si(si_), isForDebug(debug_), isVirtual(virtual_) {
- }
- };
-
- const static Sensor mNonSensor; //.getName() == "unknown",
-
// Iterate through Entry in sensor list and perform operation f on each Entry.
//
// TF is a function with the signature:
@@ -99,6 +89,16 @@
template <typename TF>
void forEachEntry(const TF& f) const;
+ const Sensor& getNonSensor() const { return mNonSensor;}
+
+ // Dumpable interface
+ virtual std::string dump() const override;
+ virtual void dump(util::ProtoOutputStream* proto) const override;
+
+ virtual ~SensorList();
+private:
+ const static Sensor mNonSensor; //.getName() == "unknown",
+
template <typename T, typename TF>
T getOne(int handle, const TF& accessor, T def = T()) const;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index f949196..9df020d 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -51,7 +51,6 @@
#include "SensorRecord.h"
#include "SensorRegistrationInfo.h"
-#include <ctime>
#include <inttypes.h>
#include <math.h>
#include <sched.h>
@@ -61,8 +60,13 @@
#include <sys/types.h>
#include <unistd.h>
+#include <ctime>
+#include <future>
+
#include <private/android_filesystem_config.h>
+using namespace std::chrono_literals;
+
namespace android {
// ---------------------------------------------------------------------------
@@ -83,6 +87,8 @@
String16 SensorService::sSensorInterfaceDescriptorPrefix =
String16("android.frameworks.sensorservice@");
AppOpsManager SensorService::sAppOpsManager;
+std::atomic_uint64_t SensorService::curProxCallbackSeq(0);
+std::atomic_uint64_t SensorService::completedCallbackSeq(0);
#define SENSOR_SERVICE_DIR "/data/system/sensor_service"
#define SENSOR_SERVICE_HMAC_KEY_FILE SENSOR_SERVICE_DIR "/hmac_key"
@@ -97,7 +103,7 @@
SensorService::SensorService()
: mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
- mWakeLockAcquired(false) {
+ mWakeLockAcquired(false), mProximityActiveCount(0) {
mUidPolicy = new UidPolicy(this);
mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
}
@@ -168,7 +174,7 @@
(1<<SENSOR_TYPE_GAME_ROTATION_VECTOR);
for (ssize_t i=0 ; i<count ; i++) {
- bool useThisSensor=true;
+ bool useThisSensor = true;
switch (list[i].type) {
case SENSOR_TYPE_ACCELEROMETER:
@@ -197,7 +203,11 @@
break;
}
if (useThisSensor) {
- registerSensor( new HardwareSensor(list[i]) );
+ if (list[i].type == SENSOR_TYPE_PROXIMITY) {
+ registerSensor(new ProximitySensor(list[i], *this));
+ } else {
+ registerSensor( new HardwareSensor(list[i]) );
+ }
}
}
@@ -670,6 +680,10 @@
bool hasAccess = hasSensorAccessLocked(conn->getUid(), conn->getOpPackageName());
conn->onSensorAccessChanged(hasAccess);
}
+ mSensors.forEachEntry([](const SensorServiceUtil::SensorList::Entry& e) {
+ e.si->willDisableAllSensors();
+ return true;
+ });
dev.disableAllSensors();
// Clear all pending flush connections for all active sensors. If one of the active
// connections has called flush() and the underlying sensor has been disabled before a
@@ -695,6 +709,10 @@
}
SensorDevice& dev(SensorDevice::getInstance());
dev.enableAllSensors();
+ mSensors.forEachEntry([](const SensorServiceUtil::SensorList::Entry& e) {
+ e.si->didEnableAllSensors();
+ return true;
+ });
for (const sp<SensorDirectConnection>& conn : connLock->getDirectConnections()) {
bool hasAccess = hasSensorAccessLocked(conn->getUid(), conn->getOpPackageName());
conn->onSensorAccessChanged(hasAccess);
@@ -1520,6 +1538,10 @@
if (err == NO_ERROR) {
mCurrentOperatingMode = NORMAL;
dev.enableAllSensors();
+ mSensors.forEachEntry([](const SensorServiceUtil::SensorList::Entry& e) {
+ e.si->didEnableAllSensors();
+ return true;
+ });
}
return err;
}
@@ -1584,6 +1606,80 @@
mConnectionHolder.removeDirectConnection(c);
}
+void SensorService::onProximityActiveLocked(bool isActive) {
+ int prevCount = mProximityActiveCount;
+ bool activeStateChanged = false;
+ if (isActive) {
+ mProximityActiveCount++;
+ activeStateChanged = prevCount == 0;
+ } else {
+ mProximityActiveCount--;
+ if (mProximityActiveCount < 0) {
+ ALOGE("Proximity active count is negative (%d)!", mProximityActiveCount);
+ }
+ activeStateChanged = prevCount > 0 && mProximityActiveCount <= 0;
+ }
+
+ if (activeStateChanged) {
+ notifyProximityStateLocked(mProximityActiveListeners);
+ }
+}
+
+void SensorService::notifyProximityStateLocked(
+ const std::vector<sp<ProximityActiveListener>>& listnrs) {
+ std::async(
+ std::launch::async,
+ [](uint64_t mySeq, bool isActive, std::vector<sp<ProximityActiveListener>> listeners) {
+ while (completedCallbackSeq.load() != mySeq - 1)
+ std::this_thread::sleep_for(1ms);
+ for (auto& listener : listeners)
+ listener->onProximityActive(isActive);
+ completedCallbackSeq++;
+ },
+ ++curProxCallbackSeq, mProximityActiveCount > 0,
+ listnrs /* (this is meant to be a copy) */
+ );
+}
+
+status_t SensorService::addProximityActiveListener(const sp<ProximityActiveListener>& callback) {
+ if (callback == nullptr) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mLock);
+
+ // Check if the callback was already added.
+ for (const auto& cb : mProximityActiveListeners) {
+ if (cb == callback) {
+ return ALREADY_EXISTS;
+ }
+ }
+
+ mProximityActiveListeners.push_back(callback);
+ std::vector<sp<ProximityActiveListener>> listener(1, callback);
+ notifyProximityStateLocked(listener);
+ return OK;
+}
+
+status_t SensorService::removeProximityActiveListener(
+ const sp<ProximityActiveListener>& callback) {
+ if (callback == nullptr) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mLock);
+
+ for (auto iter = mProximityActiveListeners.begin();
+ iter != mProximityActiveListeners.end();
+ ++iter) {
+ if (*iter == callback) {
+ mProximityActiveListeners.erase(iter);
+ return OK;
+ }
+ }
+ return NAME_NOT_FOUND;
+}
+
sp<SensorInterface> SensorService::getSensorInterfaceFromHandle(int handle) const {
return mSensors.getInterface(handle);
}
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index a563a60..def6611 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -89,9 +89,23 @@
UID_STATE_IDLE,
};
+ class ProximityActiveListener : public virtual RefBase {
+ public:
+ // Note that the callback is invoked from an async thread and can interact with the
+ // SensorService directly.
+ virtual void onProximityActive(bool isActive) = 0;
+ };
+
+ static char const* getServiceName() ANDROID_API { return "sensorservice"; }
+ SensorService() ANDROID_API;
+
void cleanupConnection(SensorEventConnection* connection);
void cleanupConnection(SensorDirectConnection* c);
+ // Call with mLock held.
+ void onProximityActiveLocked(bool isActive);
+ void notifyProximityStateLocked(const std::vector<sp<ProximityActiveListener>>& listeners);
+
status_t enable(const sp<SensorEventConnection>& connection, int handle,
nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
const String16& opPackageName);
@@ -104,6 +118,9 @@
status_t flushSensor(const sp<SensorEventConnection>& connection,
const String16& opPackageName);
+ status_t addProximityActiveListener(const sp<ProximityActiveListener>& callback) ANDROID_API;
+ status_t removeProximityActiveListener(const sp<ProximityActiveListener>& callback) ANDROID_API;
+
// Returns true if a sensor should be throttled according to our rate-throttling rules.
static bool isSensorInCappedSet(int sensorType);
@@ -305,8 +322,6 @@
};
static const char* WAKE_LOCK_NAME;
- static char const* getServiceName() ANDROID_API { return "sensorservice"; }
- SensorService() ANDROID_API;
virtual ~SensorService();
virtual void onFirstRef();
@@ -326,6 +341,7 @@
virtual int setOperationParameter(
int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints);
virtual status_t dump(int fd, const Vector<String16>& args);
+
status_t dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock) const;
String8 getSensorName(int handle) const;
String8 getSensorStringType(int handle) const;
@@ -433,6 +449,9 @@
static uint8_t sHmacGlobalKey[128];
static bool sHmacGlobalKeyIsValid;
+ static std::atomic_uint64_t curProxCallbackSeq;
+ static std::atomic_uint64_t completedCallbackSeq;
+
SensorServiceUtil::SensorList mSensors;
status_t mInitCheck;
@@ -476,6 +495,10 @@
std::map<userid_t, sp<SensorPrivacyPolicy>> mMicSensorPrivacyPolicies;
// Checks if the mic sensor privacy is enabled for the uid
bool isMicSensorPrivacyEnabledForUid(uid_t uid);
+
+ // Counts how many proximity sensors are currently active.
+ int mProximityActiveCount;
+ std::vector<sp<ProximityActiveListener>> mProximityActiveListeners;
};
} // namespace android
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index f20bfe1..e669e45 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -188,6 +188,7 @@
"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 2f2cc06..297c0b2 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/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp
index fd18c3b..0cc5f33 100644
--- a/services/surfaceflinger/EffectLayer.cpp
+++ b/services/surfaceflinger/EffectLayer.cpp
@@ -66,6 +66,7 @@
layerSettings->source.solidColor = getColor().rgb;
results.push_back(*layerSettings);
} else if (hasBlur() || drawShadows()) {
+ layerSettings->skipContentDraw = true;
results.push_back(*layerSettings);
}
@@ -126,7 +127,7 @@
bool EffectLayer::isOpaque(const Layer::State& s) const {
// Consider the layer to be opaque if its opaque flag is set or its effective
// alpha (considering the alpha of its parents as well) is 1.0;
- return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf;
+ return (s.flags & layer_state_t::eLayerOpaque) != 0 || (fillsColor() && getAlpha() == 1.0_hf);
}
ui::Dataspace EffectLayer::getDataSpace() const {
@@ -147,7 +148,7 @@
}
bool EffectLayer::hasBlur() const {
- return getBackgroundBlurRadius() > 0;
+ return getBackgroundBlurRadius() > 0 || getDrawingState().blurRegions.size() > 0;
}
} // namespace android
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index f19e2a7..9b03287 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -136,6 +136,10 @@
janks.emplace_back("Unknown jank");
jankType &= ~JankType::Unknown;
}
+ if (jankType & JankType::SurfaceFlingerStuffing) {
+ janks.emplace_back("SurfaceFlinger Stuffing");
+ jankType &= ~JankType::SurfaceFlingerStuffing;
+ }
// jankType should be 0 if all types of jank were checked for.
LOG_ALWAYS_FATAL_IF(jankType != 0, "Unrecognized jank type value 0x%x", jankType);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a7c8704..d720bcb 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -574,7 +574,8 @@
layerSettings.geometry.positionTransform = getTransform().asMatrix4();
// skip drawing content if the targetSettings indicate the content will be occluded
- layerSettings.skipContentDraw = !targetSettings.realContentIsVisible;
+ layerSettings.skipContentDraw =
+ layerSettings.skipContentDraw || !targetSettings.realContentIsVisible;
if (hasColorTransform()) {
layerSettings.colorTransform = getColorTransform();
@@ -1651,12 +1652,25 @@
return count;
}
+void Layer::setGameModeForTree(int parentGameMode) {
+ int gameMode = parentGameMode;
+ auto& currentState = getCurrentState();
+ if (currentState.metadata.has(METADATA_GAME_MODE)) {
+ gameMode = currentState.metadata.getInt32(METADATA_GAME_MODE, 0);
+ }
+ setGameMode(gameMode);
+ for (const sp<Layer>& child : mCurrentChildren) {
+ child->setGameModeForTree(gameMode);
+ }
+}
+
void Layer::addChild(const sp<Layer>& layer) {
mChildrenChanged = true;
setTransactionFlags(eTransactionNeeded);
mCurrentChildren.add(layer);
layer->setParent(this);
+ layer->setGameModeForTree(mGameMode);
updateTreeHasFrameRateVote();
}
@@ -1668,6 +1682,7 @@
const auto removeResult = mCurrentChildren.remove(layer);
updateTreeHasFrameRateVote();
+ layer->setGameModeForTree(0);
layer->updateTreeHasFrameRateVote();
return removeResult;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 66d7018..af26045 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -847,6 +847,13 @@
*/
bool hasInputInfo() const;
+ // Sets the parent's gameMode for this layer and all its children. Parent's gameMode is applied
+ // only to layers that do not have the GAME_MODE_METADATA set by WMShell. Any layer(along with
+ // its children) that has the metadata set will use the gameMode from the metadata.
+ void setGameModeForTree(int parentGameMode);
+ void setGameMode(int gameMode) { mGameMode = gameMode; };
+ int getGameMode() const { return mGameMode; }
+
virtual uid_t getOwnerUid() const { return mOwnerUid; }
pid_t getOwnerPid() { return mOwnerPid; }
@@ -1089,6 +1096,10 @@
// shadow radius is the set shadow radius, otherwise its the parent's shadow radius.
float mEffectiveShadowRadius = 0.f;
+ // Game mode for the layer. Set by WindowManagerShell, game mode is used in
+ // metrics(SurfaceFlingerStats).
+ int mGameMode = 0;
+
// A list of regions on this layer that should have blurs.
const std::vector<BlurRegion> getBlurRegions() const;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7085eaf..a86e061 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"
@@ -788,11 +789,6 @@
property_get("persist.sys.sf.color_mode", value, "0");
mForceColorMode = static_cast<ColorMode>(atoi(value));
-
- property_get("persist.sys.sf.disable_blurs", value, "0");
- bool disableBlurs = atoi(value);
- mDisableBlurs = disableBlurs;
- ALOGI_IF(disableBlurs, "Disabling blur effects, user preference.");
}
void SurfaceFlinger::startBootAnim() {
@@ -1468,6 +1464,26 @@
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 +2207,10 @@
if (mFpsReporter) {
mFpsReporter->dispatchLayerFps();
}
+
+ if (mTunnelModeEnabledReporter) {
+ mTunnelModeEnabledReporter->updateTunnelModeStatus();
+ }
hdrInfoListeners.reserve(mHdrLayerInfoListeners.size());
for (auto& [key, value] : mHdrLayerInfoListeners) {
if (value && value->hasListeners()) {
@@ -3067,6 +3087,7 @@
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.
@@ -3927,7 +3948,7 @@
if (layer->setCornerRadius(s.cornerRadius))
flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs && mSupportsBlur) {
+ if (what & layer_state_t::eBackgroundBlurRadiusChanged && mSupportsBlur) {
if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eBlurRegionsChanged) {
@@ -3992,6 +4013,13 @@
std::optional<nsecs_t> dequeueBufferTimestamp;
if (what & layer_state_t::eMetadataChanged) {
dequeueBufferTimestamp = s.metadata.getInt64(METADATA_DEQUEUE_TIME);
+ auto gameMode = s.metadata.getInt32(METADATA_GAME_MODE, -1);
+ if (gameMode != -1) {
+ // The transaction will be received on the Task layer and needs to be applied to all
+ // child layers. Child layers that are added at a later point will obtain the game mode
+ // info through addChild().
+ layer->setGameModeForTree(gameMode);
+ }
if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eColorSpaceAgnosticChanged) {
@@ -5072,6 +5100,8 @@
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 cb8d312..30d76af 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -90,6 +90,7 @@
class Client;
class EventThread;
class FpsReporter;
+class TunnelModeEnabledReporter;
class HdrLayerInfoReporter;
class HWComposer;
struct SetInputWindowsListener;
@@ -359,6 +360,7 @@
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 @@
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,
@@ -1258,8 +1264,6 @@
bool mUseHwcVirtualDisplays = false;
// If blurs should be enabled on this device.
bool mSupportsBlur = false;
- // Disable blurs, for debugging
- std::atomic<bool> mDisableBlurs = false;
// If blurs are considered expensive and should require high GPU frequency.
bool mBlursAreExpensive = false;
std::atomic<uint32_t> mFrameMissedCount = 0;
@@ -1368,6 +1372,7 @@
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 0000000..1b3ddf7
--- /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 0000000..d55507a
--- /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 b33434e..736ef30 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -57,6 +57,7 @@
"FpsTest.cpp",
"FramebufferSurfaceTest.cpp",
"FrameTimelineTest.cpp",
+ "GameModeTest.cpp",
"HWComposerTest.cpp",
"OneShotTimerTest.cpp",
"LayerHistoryTest.cpp",
@@ -86,6 +87,7 @@
"TransactionApplicationTest.cpp",
"TransactionFrameTracerTest.cpp",
"TransactionSurfaceFrameTest.cpp",
+ "TunnelModeEnabledReporterTest.cpp",
"StrongTypingTest.cpp",
"VSyncDispatchTimerQueueTest.cpp",
"VSyncDispatchRealtimeTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/GameModeTest.cpp b/services/surfaceflinger/tests/unittests/GameModeTest.cpp
new file mode 100644
index 0000000..3fa1a2c
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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 "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerMetadata.h>
+#include <gui/SurfaceComposerClient.h>
+#include <log/log.h>
+
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockVsyncController.h"
+
+namespace android {
+
+using testing::_;
+using testing::Mock;
+using testing::Return;
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+class GameModeTest : public testing::Test {
+public:
+ GameModeTest() {
+ 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();
+ setupComposer();
+ }
+
+ ~GameModeTest() {
+ 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());
+ }
+
+ sp<BufferStateLayer> createBufferStateLayer() {
+ sp<Client> client;
+ LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0,
+ LayerMetadata());
+ return new BufferStateLayer(args);
+ }
+
+ void 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));
+ }
+
+ void setupComposer() {
+ mComposer = new Hwc2::mock::Composer();
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+ Mock::VerifyAndClear(mComposer);
+ }
+
+ // Mocks the behavior of applying a transaction from WMShell
+ void setGameModeMetadata(sp<Layer> layer, int gameMode) {
+ mLayerMetadata.setInt32(METADATA_GAME_MODE, gameMode);
+ layer->setMetadata(mLayerMetadata);
+ layer->setGameModeForTree(gameMode);
+ }
+
+ TestableSurfaceFlinger mFlinger;
+ Hwc2::mock::Composer* mComposer = nullptr;
+ client_cache_t mClientCache;
+ LayerMetadata mLayerMetadata;
+};
+
+TEST_F(GameModeTest, SetGameModeSetsForAllCurrentChildren) {
+ sp<BufferStateLayer> rootLayer = createBufferStateLayer();
+ sp<BufferStateLayer> childLayer1 = createBufferStateLayer();
+ sp<BufferStateLayer> childLayer2 = createBufferStateLayer();
+ rootLayer->addChild(childLayer1);
+ rootLayer->addChild(childLayer2);
+ rootLayer->setGameModeForTree(/*gameMode*/ 2);
+
+ EXPECT_EQ(rootLayer->getGameMode(), 2);
+ EXPECT_EQ(childLayer1->getGameMode(), 2);
+ EXPECT_EQ(childLayer2->getGameMode(), 2);
+}
+
+TEST_F(GameModeTest, AddChildAppliesGameModeFromParent) {
+ sp<BufferStateLayer> rootLayer = createBufferStateLayer();
+ sp<BufferStateLayer> childLayer = createBufferStateLayer();
+ rootLayer->setGameModeForTree(/*gameMode*/ 2);
+ rootLayer->addChild(childLayer);
+
+ EXPECT_EQ(rootLayer->getGameMode(), 2);
+ EXPECT_EQ(childLayer->getGameMode(), 2);
+}
+
+TEST_F(GameModeTest, RemoveChildResetsGameMode) {
+ sp<BufferStateLayer> rootLayer = createBufferStateLayer();
+ sp<BufferStateLayer> childLayer = createBufferStateLayer();
+ rootLayer->setGameModeForTree(/*gameMode*/ 2);
+ rootLayer->addChild(childLayer);
+
+ EXPECT_EQ(rootLayer->getGameMode(), 2);
+ EXPECT_EQ(childLayer->getGameMode(), 2);
+
+ rootLayer->removeChild(childLayer);
+ EXPECT_EQ(childLayer->getGameMode(), 0);
+}
+
+TEST_F(GameModeTest, ReparentingDoesNotOverrideMetadata) {
+ sp<BufferStateLayer> rootLayer = createBufferStateLayer();
+ sp<BufferStateLayer> childLayer1 = createBufferStateLayer();
+ sp<BufferStateLayer> childLayer2 = createBufferStateLayer();
+ rootLayer->setGameModeForTree(/*gameMode*/ 1);
+ rootLayer->addChild(childLayer1);
+
+ setGameModeMetadata(childLayer2, /*gameMode*/ 2);
+ rootLayer->addChild(childLayer2);
+
+ EXPECT_EQ(rootLayer->getGameMode(), 1);
+ EXPECT_EQ(childLayer1->getGameMode(), 1);
+ EXPECT_EQ(childLayer2->getGameMode(), 2);
+
+ rootLayer->removeChild(childLayer2);
+ EXPECT_EQ(childLayer2->getGameMode(), 2);
+}
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index d004b9d..a551248 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -276,6 +276,7 @@
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 0000000..d7d7ea7
--- /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