Merge changes I65b2b48d,I0d41ba77 into main
* changes:
[20/n Dispatcher refactor] Allow access to all TouchedWindowHandles
[19/n Dispatcher refactor] Remove findTouchStateWindowAndDisplay
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index 6d14d56..277300d 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -772,8 +772,8 @@
break;
case 'i':
- displayId = DisplayId::fromValue<PhysicalDisplayId>(atoll(optarg));
- if (!displayId) {
+ displayId = PhysicalDisplayId::fromValue(atoll(optarg));
+ if (std::find(ids.begin(), ids.end(), displayId) == ids.end()) {
fprintf(stderr, "Invalid display ID: %s.\n", optarg);
exit(4);
}
diff --git a/include/android/input.h b/include/android/input.h
index ee98d7a..5f44550 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -849,6 +849,7 @@
* Refer to the documentation on the MotionEvent class for descriptions of each button.
*/
enum {
+ // LINT.IfChange(AMOTION_EVENT_BUTTON)
/** primary */
AMOTION_EVENT_BUTTON_PRIMARY = 1 << 0,
/** secondary */
@@ -861,6 +862,7 @@
AMOTION_EVENT_BUTTON_FORWARD = 1 << 4,
AMOTION_EVENT_BUTTON_STYLUS_PRIMARY = 1 << 5,
AMOTION_EVENT_BUTTON_STYLUS_SECONDARY = 1 << 6,
+ // LINT.ThenChange(/frameworks/native/libs/input/rust/input.rs)
};
/**
diff --git a/include/input/InputVerifier.h b/include/input/InputVerifier.h
index 14dd463..7d3fb46 100644
--- a/include/input/InputVerifier.h
+++ b/include/input/InputVerifier.h
@@ -47,9 +47,10 @@
InputVerifier(const std::string& name);
android::base::Result<void> processMovement(int32_t deviceId, int32_t source, int32_t action,
- uint32_t pointerCount,
+ int32_t actionButton, uint32_t pointerCount,
const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords, int32_t flags);
+ const PointerCoords* pointerCoords, int32_t flags,
+ int32_t buttonState);
void resetDevice(int32_t deviceId);
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 152c815..83f4719 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -147,9 +147,11 @@
data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
data.writeInt32(uid);
data.writeString16(callingPackage);
- remote()->transact(IS_UID_ACTIVE_TRANSACTION, data, &reply);
+ status_t err = remote()->transact(IS_UID_ACTIVE_TRANSACTION, data, &reply);
// fail on exception
- if (reply.readExceptionCode() != 0) return false;
+ if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+ return false;
+ }
return reply.readInt32() == 1;
}
@@ -159,9 +161,9 @@
data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
data.writeInt32(uid);
data.writeString16(callingPackage);
- remote()->transact(GET_UID_PROCESS_STATE_TRANSACTION, data, &reply);
+ status_t err = remote()->transact(GET_UID_PROCESS_STATE_TRANSACTION, data, &reply);
// fail on exception
- if (reply.readExceptionCode() != 0) {
+ if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
return ActivityManager::PROCESS_STATE_UNKNOWN;
}
return reply.readInt32();
@@ -192,7 +194,7 @@
data.writeInt32(appPid);
status_t err = remote()->transact(LOG_FGS_API_BEGIN_TRANSACTION, data, &reply,
IBinder::FLAG_ONEWAY);
- if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+ if (err != NO_ERROR) {
ALOGD("%s: FGS Logger Transaction failed, %d", __func__, err);
return err;
}
@@ -207,7 +209,7 @@
data.writeInt32(appPid);
status_t err =
remote()->transact(LOG_FGS_API_END_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
- if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+ if (err != NO_ERROR) {
ALOGD("%s: FGS Logger Transaction failed, %d", __func__, err);
return err;
}
@@ -224,7 +226,7 @@
data.writeInt32(appPid);
status_t err = remote()->transact(LOG_FGS_API_STATE_CHANGED_TRANSACTION, data, &reply,
IBinder::FLAG_ONEWAY);
- if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+ if (err != NO_ERROR) {
ALOGD("%s: FGS Logger Transaction failed, %d", __func__, err);
return err;
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 44aac9b..ebfc62f 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -67,7 +67,6 @@
reserved(0),
cornerRadius(0.0f),
clientDrawnCornerRadius(0.0f),
- clientDrawnShadowRadius(0.0f),
backgroundBlurRadius(0),
color(0),
bufferTransform(0),
@@ -143,7 +142,6 @@
SAFE_PARCEL(output.write, colorTransform.asArray(), 16 * sizeof(float));
SAFE_PARCEL(output.writeFloat, cornerRadius);
SAFE_PARCEL(output.writeFloat, clientDrawnCornerRadius);
- SAFE_PARCEL(output.writeFloat, clientDrawnShadowRadius);
SAFE_PARCEL(output.writeUint32, backgroundBlurRadius);
SAFE_PARCEL(output.writeParcelable, metadata);
SAFE_PARCEL(output.writeFloat, bgColor.r);
@@ -279,7 +277,6 @@
SAFE_PARCEL(input.read, &colorTransform, 16 * sizeof(float));
SAFE_PARCEL(input.readFloat, &cornerRadius);
SAFE_PARCEL(input.readFloat, &clientDrawnCornerRadius);
- SAFE_PARCEL(input.readFloat, &clientDrawnShadowRadius);
SAFE_PARCEL(input.readUint32, &backgroundBlurRadius);
SAFE_PARCEL(input.readParcelable, &metadata);
@@ -606,10 +603,6 @@
what |= eClientDrawnCornerRadiusChanged;
clientDrawnCornerRadius = other.clientDrawnCornerRadius;
}
- if (other.what & eClientDrawnShadowsChanged) {
- what |= eClientDrawnShadowsChanged;
- clientDrawnShadowRadius = other.clientDrawnShadowRadius;
- }
if (other.what & eBackgroundBlurRadiusChanged) {
what |= eBackgroundBlurRadiusChanged;
backgroundBlurRadius = other.backgroundBlurRadius;
@@ -824,7 +817,6 @@
CHECK_DIFF(diff, eLayerStackChanged, other, layerStack);
CHECK_DIFF(diff, eCornerRadiusChanged, other, cornerRadius);
CHECK_DIFF(diff, eClientDrawnCornerRadiusChanged, other, clientDrawnCornerRadius);
- CHECK_DIFF(diff, eClientDrawnShadowsChanged, other, clientDrawnShadowRadius);
CHECK_DIFF(diff, eBackgroundBlurRadiusChanged, other, backgroundBlurRadius);
if (other.what & eBlurRegionsChanged) diff |= eBlurRegionsChanged;
if (other.what & eRelativeLayerChanged) {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 852885b..37ed23b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1415,9 +1415,8 @@
ComposerServiceAIDL::getComposerService()->getPhysicalDisplayIds(&displayIds);
if (status.isOk()) {
physicalDisplayIds.reserve(displayIds.size());
- for (auto item : displayIds) {
- auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(item));
- physicalDisplayIds.push_back(*id);
+ for (auto id : displayIds) {
+ physicalDisplayIds.push_back(PhysicalDisplayId::fromValue(static_cast<uint64_t>(id)));
}
}
return physicalDisplayIds;
@@ -1688,17 +1687,6 @@
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setClientDrawnShadowRadius(
- const sp<SurfaceControl>& sc, float clientDrawnShadowRadius) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
- s->what |= layer_state_t::eClientDrawnShadowsChanged;
- s->clientDrawnShadowRadius = clientDrawnShadowRadius;
- return *this;
-}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackgroundBlurRadius(
const sp<SurfaceControl>& sc, int backgroundBlurRadius) {
layer_state_t* s = getLayerState(sc);
diff --git a/libs/gui/include/gui/InputTransferToken.h b/libs/gui/include/gui/InputTransferToken.h
index 6530b50..fb4aaa7 100644
--- a/libs/gui/include/gui/InputTransferToken.h
+++ b/libs/gui/include/gui/InputTransferToken.h
@@ -25,7 +25,7 @@
namespace android {
struct InputTransferToken : public RefBase, Parcelable {
public:
- InputTransferToken() { mToken = new BBinder(); }
+ InputTransferToken() { mToken = sp<BBinder>::make(); }
InputTransferToken(const sp<IBinder>& token) { mToken = token; }
@@ -50,4 +50,4 @@
return token1->mToken == token2->mToken;
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 1002614..d04b861 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -232,7 +232,6 @@
ePictureProfileHandleChanged = 0x80000'00000000,
eAppContentPriorityChanged = 0x100000'00000000,
eClientDrawnCornerRadiusChanged = 0x200000'00000000,
- eClientDrawnShadowsChanged = 0x400000'00000000,
};
layer_state_t();
@@ -276,7 +275,7 @@
layer_state_t::eColorSpaceAgnosticChanged | layer_state_t::eColorTransformChanged |
layer_state_t::eCornerRadiusChanged | layer_state_t::eDimmingEnabledChanged |
layer_state_t::eHdrMetadataChanged | layer_state_t::eShadowRadiusChanged |
- layer_state_t::eClientDrawnShadowsChanged | layer_state_t::eStretchChanged |
+ layer_state_t::eStretchChanged |
layer_state_t::ePictureProfileHandleChanged | layer_state_t::eAppContentPriorityChanged;
// Changes which invalidates the layer's visible region in CE.
@@ -336,7 +335,6 @@
matrix22_t matrix;
float cornerRadius;
float clientDrawnCornerRadius;
- float clientDrawnShadowRadius;
uint32_t backgroundBlurRadius;
sp<SurfaceControl> relativeLayerSurfaceControl;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index d30a830..10225cc 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -569,10 +569,6 @@
// radius is drawn by the client and not SurfaceFlinger.
Transaction& setClientDrawnCornerRadius(const sp<SurfaceControl>& sc,
float clientDrawnCornerRadius);
- // Sets the client drawn shadow radius for the layer. This indicates that the shadows
- // are drawn by the client and not SurfaceFlinger.
- Transaction& setClientDrawnShadowRadius(const sp<SurfaceControl>& sc,
- float clientDrawnShadowRadius);
Transaction& setBackgroundBlurRadius(const sp<SurfaceControl>& sc,
int backgroundBlurRadius);
Transaction& setBlurRegions(const sp<SurfaceControl>& sc,
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index cd6fe90..d2e4320 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -133,6 +133,13 @@
"--allowlist-var=AMOTION_EVENT_ACTION_POINTER_DOWN",
"--allowlist-var=AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT",
"--allowlist-var=AMOTION_EVENT_ACTION_UP",
+ "--allowlist-var=AMOTION_EVENT_BUTTON_BACK",
+ "--allowlist-var=AMOTION_EVENT_BUTTON_FORWARD",
+ "--allowlist-var=AMOTION_EVENT_BUTTON_PRIMARY",
+ "--allowlist-var=AMOTION_EVENT_BUTTON_SECONDARY",
+ "--allowlist-var=AMOTION_EVENT_BUTTON_STYLUS_PRIMARY",
+ "--allowlist-var=AMOTION_EVENT_BUTTON_STYLUS_SECONDARY",
+ "--allowlist-var=AMOTION_EVENT_BUTTON_TERTIARY",
"--allowlist-var=MAX_POINTER_ID",
"--verbose",
],
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 56ccaab..d388d48 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -651,9 +651,9 @@
const status_t status = mChannel->sendMessage(&msg);
if (status == OK && verifyEvents()) {
- Result<void> result =
- mInputVerifier.processMovement(deviceId, source, action, pointerCount,
- pointerProperties, pointerCoords, flags);
+ Result<void> result = mInputVerifier.processMovement(deviceId, source, action, actionButton,
+ pointerCount, pointerProperties,
+ pointerCoords, flags, buttonState);
if (!result.ok()) {
LOG(ERROR) << "Bad stream: " << result.error();
return BAD_VALUE;
diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp
index cec2445..7811ace 100644
--- a/libs/input/InputVerifier.cpp
+++ b/libs/input/InputVerifier.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "InputVerifier"
#include <android-base/logging.h>
+#include <com_android_input_flags.h>
#include <input/InputVerifier.h>
#include "input_cxx_bridge.rs.h"
@@ -26,17 +27,23 @@
using DeviceId = int32_t;
+namespace input_flags = com::android::input::flags;
+
namespace android {
// --- InputVerifier ---
InputVerifier::InputVerifier(const std::string& name)
- : mVerifier(android::input::verifier::create(rust::String::lossy(name))){};
+ : mVerifier(
+ android::input::verifier::create(rust::String::lossy(name),
+ input_flags::enable_button_state_verification())) {
+}
Result<void> InputVerifier::processMovement(DeviceId deviceId, int32_t source, int32_t action,
- uint32_t pointerCount,
+ int32_t actionButton, uint32_t pointerCount,
const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords, int32_t flags) {
+ const PointerCoords* pointerCoords, int32_t flags,
+ int32_t buttonState) {
std::vector<RustPointerProperties> rpp;
for (size_t i = 0; i < pointerCount; i++) {
rpp.emplace_back(RustPointerProperties{.id = pointerProperties[i].id});
@@ -44,7 +51,9 @@
rust::Slice<const RustPointerProperties> properties{rpp.data(), rpp.size()};
rust::String errorMessage =
android::input::verifier::process_movement(*mVerifier, deviceId, source, action,
- properties, static_cast<uint32_t>(flags));
+ actionButton, properties,
+ static_cast<uint32_t>(flags),
+ static_cast<uint32_t>(buttonState));
if (errorMessage.empty()) {
return {};
} else {
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 72a6fdf..4e187ed 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -16,6 +16,16 @@
}
flag {
+ name: "enable_button_state_verification"
+ namespace: "input"
+ description: "Set to true to enable crashing whenever bad inbound events are going into InputDispatcher"
+ bug: "392870542"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "remove_input_channel_from_windowstate"
namespace: "input"
description: "Do not store a copy of input channel inside WindowState."
diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs
index 6956a84..6eb2d73 100644
--- a/libs/input/rust/input.rs
+++ b/libs/input/rust/input.rs
@@ -101,6 +101,7 @@
/// A rust enum representation of a MotionEvent action.
#[repr(u32)]
+#[derive(Eq, PartialEq)]
pub enum MotionAction {
/// ACTION_DOWN
Down = input_bindgen::AMOTION_EVENT_ACTION_DOWN,
@@ -194,6 +195,27 @@
}
bitflags! {
+ /// MotionEvent buttons.
+ #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
+ pub struct MotionButton: u32 {
+ /// Primary button (e.g. the left mouse button)
+ const Primary = input_bindgen::AMOTION_EVENT_BUTTON_PRIMARY;
+ /// Secondary button (e.g. the right mouse button)
+ const Secondary = input_bindgen::AMOTION_EVENT_BUTTON_SECONDARY;
+ /// Tertiary button (e.g. the middle mouse button)
+ const Tertiary = input_bindgen::AMOTION_EVENT_BUTTON_TERTIARY;
+ /// Back button
+ const Back = input_bindgen::AMOTION_EVENT_BUTTON_BACK;
+ /// Forward button
+ const Forward = input_bindgen::AMOTION_EVENT_BUTTON_FORWARD;
+ /// Primary stylus button
+ const StylusPrimary = input_bindgen::AMOTION_EVENT_BUTTON_STYLUS_PRIMARY;
+ /// Secondary stylus button
+ const StylusSecondary = input_bindgen::AMOTION_EVENT_BUTTON_STYLUS_SECONDARY;
+ }
+}
+
+bitflags! {
/// MotionEvent flags.
/// The source of truth for the flag definitions are the MotionEventFlag AIDL enum.
/// The flag values are redefined here as a bitflags API.
diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs
index bddd2a7..6d94316 100644
--- a/libs/input/rust/input_verifier.rs
+++ b/libs/input/rust/input_verifier.rs
@@ -17,20 +17,30 @@
//! Contains the InputVerifier, used to validate a stream of input events.
use crate::ffi::RustPointerProperties;
-use crate::input::{DeviceId, MotionAction, MotionFlags, Source, SourceClass};
+use crate::input::{DeviceId, MotionAction, MotionButton, MotionFlags, Source, SourceClass};
use log::info;
use std::collections::HashMap;
use std::collections::HashSet;
fn verify_event(
action: MotionAction,
+ action_button: MotionButton,
pointer_properties: &[RustPointerProperties],
flags: &MotionFlags,
+ verify_buttons: bool,
) -> Result<(), String> {
let pointer_count = pointer_properties.len();
if pointer_count < 1 {
return Err(format!("Invalid {} event: no pointers", action));
}
+ if action_button != MotionButton::empty()
+ && action != MotionAction::ButtonPress
+ && action != MotionAction::ButtonRelease
+ {
+ return Err(format!(
+ "Invalid {action} event: has action button {action_button:?} but is not a button action"
+ ));
+ }
match action {
MotionAction::Down
| MotionAction::HoverEnter
@@ -58,22 +68,126 @@
}
}
+ MotionAction::ButtonPress | MotionAction::ButtonRelease => {
+ if verify_buttons {
+ let button_count = action_button.iter().count();
+ if button_count != 1 {
+ return Err(format!(
+ "Invalid {action} event: must specify a single action button, not \
+ {button_count} action buttons"
+ ));
+ }
+ }
+ }
+
_ => {}
}
Ok(())
}
+/// Keeps track of the button state for a single device and verifies events against it.
+#[derive(Default)]
+struct ButtonVerifier {
+ /// The current button state of the device.
+ button_state: MotionButton,
+
+ /// The set of "pending buttons", which were seen in the last DOWN event's button state but
+ /// for which we haven't seen BUTTON_PRESS events yet.
+ ///
+ /// We allow DOWN events to include buttons in their state for which BUTTON_PRESS events haven't
+ /// been sent yet. In that case, the DOWN should be immediately followed by BUTTON_PRESS events
+ /// for those buttons, building up to a button state matching that of the DOWN. For example, if
+ /// the user presses the primary and secondary buttons at exactly the same time, we'd expect
+ /// this sequence:
+ ///
+ /// | Action | Action button | Button state |
+ /// |----------------|---------------|------------------------|
+ /// | `HOVER_EXIT` | - | - |
+ /// | `DOWN` | - | `PRIMARY`, `SECONDARY` |
+ /// | `BUTTON_PRESS` | `PRIMARY` | `PRIMARY` |
+ /// | `BUTTON_PRESS` | `SECONDARY` | `PRIMARY`, `SECONDARY` |
+ /// | `MOVE` | - | `PRIMARY`, `SECONDARY` |
+ pending_buttons: MotionButton,
+}
+
+impl ButtonVerifier {
+ pub fn process_action(
+ &mut self,
+ action: MotionAction,
+ action_button: MotionButton,
+ button_state: MotionButton,
+ ) -> Result<(), String> {
+ if !self.pending_buttons.is_empty() {
+ // We just saw a DOWN with some additional buttons in its state, so it should be
+ // immediately followed by ButtonPress events for those buttons.
+ if action != MotionAction::ButtonPress || !self.pending_buttons.contains(action_button)
+ {
+ return Err(format!(
+ "After DOWN event, expected BUTTON_PRESS event(s) for {:?}, but got {} with \
+ action button {:?}",
+ self.pending_buttons, action, action_button
+ ));
+ } else {
+ self.pending_buttons -= action_button;
+ }
+ }
+ let expected_state = match action {
+ MotionAction::Down => {
+ if self.button_state - button_state != MotionButton::empty() {
+ return Err(format!(
+ "DOWN event button state is missing {:?}",
+ self.button_state - button_state
+ ));
+ }
+ self.pending_buttons = button_state - self.button_state;
+ // We've already checked that the state isn't missing any already-down buttons, and
+ // extra buttons are valid on DOWN actions, so bypass the expected state check.
+ button_state
+ }
+ MotionAction::ButtonPress => {
+ if self.button_state.contains(action_button) {
+ return Err(format!(
+ "Duplicate BUTTON_PRESS; button state already contains {action_button:?}"
+ ));
+ }
+ self.button_state | action_button
+ }
+ MotionAction::ButtonRelease => {
+ if !self.button_state.contains(action_button) {
+ return Err(format!(
+ "Invalid BUTTON_RELEASE; button state doesn't contain {action_button:?}"
+ ));
+ }
+ self.button_state - action_button
+ }
+ _ => self.button_state,
+ };
+ if button_state != expected_state {
+ return Err(format!(
+ "Expected {action} button state to be {expected_state:?}, but was {button_state:?}"
+ ));
+ }
+ // DOWN events can have pending buttons, so don't update the state for them.
+ if action != MotionAction::Down {
+ self.button_state = button_state;
+ }
+ Ok(())
+ }
+}
+
/// The InputVerifier is used to validate a stream of input events.
pub struct InputVerifier {
name: String,
should_log: bool,
+ verify_buttons: bool,
touching_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>,
hovering_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>,
+ button_verifier_by_device: HashMap<DeviceId, ButtonVerifier>,
}
impl InputVerifier {
/// Create a new InputVerifier.
- pub fn new(name: &str, should_log: bool) -> Self {
+ pub fn new(name: &str, should_log: bool, verify_buttons: bool) -> Self {
logger::init(
logger::Config::default()
.with_tag_on_device("InputVerifier")
@@ -82,20 +196,25 @@
Self {
name: name.to_owned(),
should_log,
+ verify_buttons,
touching_pointer_ids_by_device: HashMap::new(),
hovering_pointer_ids_by_device: HashMap::new(),
+ button_verifier_by_device: HashMap::new(),
}
}
/// Process a pointer movement event from an InputDevice.
/// If the event is not valid, we return an error string that describes the issue.
+ #[allow(clippy::too_many_arguments)]
pub fn process_movement(
&mut self,
device_id: DeviceId,
source: Source,
action: u32,
+ action_button: MotionButton,
pointer_properties: &[RustPointerProperties],
flags: MotionFlags,
+ button_state: MotionButton,
) -> Result<(), String> {
if !source.is_from_class(SourceClass::Pointer) {
// Skip non-pointer sources like MOUSE_RELATIVE for now
@@ -112,7 +231,21 @@
);
}
- verify_event(action.into(), pointer_properties, &flags)?;
+ verify_event(
+ action.into(),
+ action_button,
+ pointer_properties,
+ &flags,
+ self.verify_buttons,
+ )?;
+
+ if self.verify_buttons {
+ self.button_verifier_by_device.entry(device_id).or_default().process_action(
+ action.into(),
+ action_button,
+ button_state,
+ )?;
+ }
match action.into() {
MotionAction::Down => {
@@ -286,6 +419,7 @@
#[cfg(test)]
mod tests {
+ use crate::input::MotionButton;
use crate::input_verifier::InputVerifier;
use crate::DeviceId;
use crate::MotionFlags;
@@ -297,7 +431,8 @@
* Send a DOWN event with 2 pointers and ensure that it's marked as invalid.
*/
fn bad_down_event() {
- let mut verifier = InputVerifier::new("Test", /*should_log*/ true);
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ true, /*verify_buttons*/ true);
let pointer_properties =
Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
assert!(verifier
@@ -305,23 +440,28 @@
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_err());
}
#[test]
fn single_pointer_stream() {
- let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
.process_movement(
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
assert!(verifier
@@ -329,8 +469,10 @@
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_MOVE,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
assert!(verifier
@@ -338,23 +480,28 @@
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_UP,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
}
#[test]
fn two_pointer_stream() {
- let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
.process_movement(
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
// POINTER 1 DOWN
@@ -366,8 +513,10 @@
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN
| (1 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ MotionButton::empty(),
&two_pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
// POINTER 0 UP
@@ -377,8 +526,10 @@
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP
| (0 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ MotionButton::empty(),
&two_pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
// ACTION_UP for pointer id=1
@@ -388,23 +539,28 @@
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_UP,
+ MotionButton::empty(),
&pointer_1_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
}
#[test]
fn multi_device_stream() {
- let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
.process_movement(
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
assert!(verifier
@@ -412,8 +568,10 @@
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_MOVE,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
assert!(verifier
@@ -421,8 +579,10 @@
DeviceId(2),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
assert!(verifier
@@ -430,8 +590,10 @@
DeviceId(2),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_MOVE,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
assert!(verifier
@@ -439,23 +601,28 @@
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_UP,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
}
#[test]
fn action_cancel() {
- let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
.process_movement(
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
assert!(verifier
@@ -463,23 +630,28 @@
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::CANCELED,
+ MotionButton::empty(),
)
.is_ok());
}
#[test]
fn invalid_action_cancel() {
- let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
.process_movement(
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
assert!(verifier
@@ -487,38 +659,46 @@
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(), // forgot to set FLAG_CANCELED
+ MotionButton::empty(),
)
.is_err());
}
#[test]
fn invalid_up() {
- let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
.process_movement(
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_UP,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_err());
}
#[test]
fn correct_hover_sequence() {
- let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
.process_movement(
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
@@ -527,8 +707,10 @@
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
@@ -537,8 +719,10 @@
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
@@ -547,23 +731,28 @@
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
}
#[test]
fn double_hover_enter() {
- let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
.process_movement(
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
@@ -572,8 +761,10 @@
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_err());
}
@@ -582,15 +773,18 @@
// MOUSE_RELATIVE, which is used during pointer capture. The verifier should allow such event.
#[test]
fn relative_mouse_move() {
- let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
.process_movement(
DeviceId(2),
Source::MouseRelative,
input_bindgen::AMOTION_EVENT_ACTION_MOVE,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
}
@@ -598,15 +792,18 @@
// Send a MOVE event with incorrect number of pointers (one of the pointers is missing).
#[test]
fn move_with_wrong_number_of_pointers() {
- let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
.process_movement(
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
// POINTER 1 DOWN
@@ -618,8 +815,10 @@
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN
| (1 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ MotionButton::empty(),
&two_pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_ok());
// MOVE event with 1 pointer missing (the pointer with id = 1). It should be rejected
@@ -628,8 +827,487 @@
DeviceId(1),
Source::Touchscreen,
input_bindgen::AMOTION_EVENT_ACTION_MOVE,
+ MotionButton::empty(),
&pointer_properties,
MotionFlags::empty(),
+ MotionButton::empty(),
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn correct_button_press() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Primary,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary,
+ )
+ .is_ok());
+ }
+
+ #[test]
+ fn button_press_without_action_button() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::empty(),
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn button_press_with_multiple_action_buttons() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Back | MotionButton::Forward,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Back | MotionButton::Forward,
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn button_press_without_action_button_in_state() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Primary,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::empty(),
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn button_release_with_action_button_in_state() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Primary,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary,
+ )
+ .is_ok());
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE,
+ MotionButton::Primary,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary,
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn nonbutton_action_with_action_button() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
+ MotionButton::Primary,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::empty(),
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn nonbutton_action_with_action_button_and_state() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
+ MotionButton::Primary,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary,
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn nonbutton_action_with_button_state_change() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::empty(),
+ )
+ .is_ok());
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Back,
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn nonbutton_action_missing_button_state() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::empty(),
+ )
+ .is_ok());
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Back,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Back,
+ )
+ .is_ok());
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::empty(),
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn up_without_button_release() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary,
+ )
+ .is_ok());
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Primary,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary,
+ )
+ .is_ok());
+ // This UP event shouldn't change the button state; a BUTTON_RELEASE before it should.
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_UP,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::empty(),
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn button_press_for_already_pressed_button() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Back,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Back,
+ )
+ .is_ok());
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Back,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Back,
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn button_release_for_unpressed_button() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE,
+ MotionButton::Back,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::empty(),
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn correct_multiple_button_presses_without_down() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Back,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Back,
+ )
+ .is_ok());
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Forward,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Back | MotionButton::Forward,
+ )
+ .is_ok());
+ }
+
+ #[test]
+ fn correct_down_with_button_press() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary | MotionButton::Secondary,
+ )
+ .is_ok());
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Primary,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary,
+ )
+ .is_ok());
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Secondary,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary | MotionButton::Secondary,
+ )
+ .is_ok());
+ // Also check that the MOVE afterwards is OK, as that's where errors would be raised if not
+ // enough BUTTON_PRESSes were sent.
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_MOVE,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary | MotionButton::Secondary,
+ )
+ .is_ok());
+ }
+
+ #[test]
+ fn down_with_button_state_change_not_followed_by_button_press() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary,
+ )
+ .is_ok());
+ // The DOWN event itself is OK, but it needs to be immediately followed by a BUTTON_PRESS.
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_MOVE,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary,
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn down_with_button_state_change_not_followed_by_enough_button_presses() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary | MotionButton::Secondary,
+ )
+ .is_ok());
+ // The DOWN event itself is OK, but it needs to be immediately followed by two
+ // BUTTON_PRESSes, one for each button.
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Primary,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary,
+ )
+ .is_ok());
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_MOVE,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Primary,
+ )
+ .is_err());
+ }
+
+ #[test]
+ fn down_missing_already_pressed_button() {
+ let mut verifier =
+ InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
+ let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ MotionButton::Back,
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::Back,
+ )
+ .is_ok());
+ assert!(verifier
+ .process_movement(
+ DeviceId(1),
+ Source::Mouse,
+ input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+ MotionButton::empty(),
+ &pointer_properties,
+ MotionFlags::empty(),
+ MotionButton::empty(),
)
.is_err());
}
diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs
index 4f4ea85..6db4356 100644
--- a/libs/input/rust/lib.rs
+++ b/libs/input/rust/lib.rs
@@ -24,8 +24,8 @@
pub use data_store::{DataStore, DefaultFileReaderWriter};
pub use input::{
- DeviceClass, DeviceId, InputDevice, KeyboardType, ModifierState, MotionAction, MotionFlags,
- Source,
+ DeviceClass, DeviceId, InputDevice, KeyboardType, ModifierState, MotionAction, MotionButton,
+ MotionFlags, Source,
};
pub use input_verifier::InputVerifier;
pub use keyboard_classifier::KeyboardClassifier;
@@ -57,14 +57,17 @@
/// ```
type InputVerifier;
#[cxx_name = create]
- fn create_input_verifier(name: String) -> Box<InputVerifier>;
+ fn create_input_verifier(name: String, verify_buttons: bool) -> Box<InputVerifier>;
+ #[allow(clippy::too_many_arguments)]
fn process_movement(
verifier: &mut InputVerifier,
device_id: i32,
source: u32,
action: u32,
+ action_button: u32,
pointer_properties: &[RustPointerProperties],
flags: u32,
+ button_state: u32,
) -> String;
fn reset_device(verifier: &mut InputVerifier, device_id: i32);
}
@@ -115,17 +118,20 @@
use crate::ffi::{RustInputDeviceIdentifier, RustPointerProperties};
-fn create_input_verifier(name: String) -> Box<InputVerifier> {
- Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents")))
+fn create_input_verifier(name: String, verify_buttons: bool) -> Box<InputVerifier> {
+ Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents"), verify_buttons))
}
+#[allow(clippy::too_many_arguments)]
fn process_movement(
verifier: &mut InputVerifier,
device_id: i32,
source: u32,
action: u32,
+ action_button: u32,
pointer_properties: &[RustPointerProperties],
flags: u32,
+ button_state: u32,
) -> String {
let motion_flags = MotionFlags::from_bits(flags);
if motion_flags.is_none() {
@@ -135,12 +141,28 @@
flags
);
}
+ let motion_action_button = MotionButton::from_bits(action_button);
+ if motion_action_button.is_none() {
+ panic!(
+ "The conversion of action button 0x{action_button:08x} failed, please check if some \
+ buttons need to be added to MotionButton."
+ );
+ }
+ let motion_button_state = MotionButton::from_bits(button_state);
+ if motion_button_state.is_none() {
+ panic!(
+ "The conversion of button state 0x{button_state:08x} failed, please check if some \
+ buttons need to be added to MotionButton."
+ );
+ }
let result = verifier.process_movement(
DeviceId(device_id),
Source::from_bits(source).unwrap(),
action,
+ motion_action_button.unwrap(),
pointer_properties,
motion_flags.unwrap(),
+ motion_button_state.unwrap(),
);
match result {
Ok(()) => "".to_string(),
diff --git a/libs/input/tests/InputVerifier_test.cpp b/libs/input/tests/InputVerifier_test.cpp
index 5bb1d56..8e0d906 100644
--- a/libs/input/tests/InputVerifier_test.cpp
+++ b/libs/input/tests/InputVerifier_test.cpp
@@ -49,9 +49,9 @@
const Result<void> result =
verifier.processMovement(/*deviceId=*/0, AINPUT_SOURCE_CLASS_POINTER,
- AMOTION_EVENT_ACTION_DOWN,
+ AMOTION_EVENT_ACTION_DOWN, /*actionButton=*/0,
/*pointerCount=*/properties.size(), properties.data(),
- coords.data(), /*flags=*/0);
+ coords.data(), /*flags=*/0, /*buttonState=*/0);
ASSERT_RESULT_OK(result);
}
diff --git a/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp
index 897f5cf..ff96b08 100644
--- a/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp
+++ b/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp
@@ -39,12 +39,36 @@
namespace skia {
KawaseBlurDualFilter::KawaseBlurDualFilter() : BlurFilter() {
- // A shader to sample each vertex of a unit regular heptagon
- // plus the original fragment coordinate.
- SkString blurString(R"(
+ // A shader to sample each vertex of a square, plus the original fragment coordinate,
+ // using a total of 5 samples.
+ SkString lowSampleBlurString(R"(
uniform shader child;
uniform float in_blurOffset;
uniform float in_crossFade;
+ uniform float in_weightedCrossFade;
+
+ const float2 STEP_0 = float2( 0.707106781, 0.707106781);
+ const float2 STEP_1 = float2( 0.707106781, -0.707106781);
+ const float2 STEP_2 = float2(-0.707106781, -0.707106781);
+ const float2 STEP_3 = float2(-0.707106781, 0.707106781);
+
+ half4 main(float2 xy) {
+ half3 c = child.eval(xy).rgb;
+
+ c += child.eval(xy + STEP_0 * in_blurOffset).rgb;
+ c += child.eval(xy + STEP_1 * in_blurOffset).rgb;
+ c += child.eval(xy + STEP_2 * in_blurOffset).rgb;
+ c += child.eval(xy + STEP_3 * in_blurOffset).rgb;
+
+ return half4(c * in_weightedCrossFade, in_crossFade);
+ }
+ )");
+
+ // A shader to sample each vertex of a unit regular heptagon, plus the original fragment
+ // coordinate, using a total of 8 samples.
+ SkString highSampleBlurString(R"(
+ uniform shader child;
+ uniform float in_blurOffset;
const float2 STEP_0 = float2( 1.0, 0.0);
const float2 STEP_1 = float2( 0.623489802, 0.781831482);
@@ -65,39 +89,46 @@
c += child.eval(xy + STEP_5 * in_blurOffset).rgb;
c += child.eval(xy + STEP_6 * in_blurOffset).rgb;
- return half4(c * 0.125 * in_crossFade, in_crossFade);
+ return half4(c * 0.125, 1.0);
}
)");
- auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString);
- LOG_ALWAYS_FATAL_IF(!blurEffect, "RuntimeShader error: %s", error.c_str());
- mBlurEffect = std::move(blurEffect);
+ auto [lowSampleBlurEffect, error] = SkRuntimeEffect::MakeForShader(lowSampleBlurString);
+ auto [highSampleBlurEffect, error2] = SkRuntimeEffect::MakeForShader(highSampleBlurString);
+ LOG_ALWAYS_FATAL_IF(!lowSampleBlurEffect, "RuntimeShader error: %s", error.c_str());
+ LOG_ALWAYS_FATAL_IF(!highSampleBlurEffect, "RuntimeShader error: %s", error2.c_str());
+ mLowSampleBlurEffect = std::move(lowSampleBlurEffect);
+ mHighSampleBlurEffect = std::move(highSampleBlurEffect);
}
void KawaseBlurDualFilter::blurInto(const sk_sp<SkSurface>& drawSurface,
const sk_sp<SkImage>& readImage, const float radius,
- const float alpha) const {
+ const float alpha,
+ const sk_sp<SkRuntimeEffect>& blurEffect) const {
const float scale = static_cast<float>(drawSurface->width()) / readImage->width();
SkMatrix blurMatrix = SkMatrix::Scale(scale, scale);
blurInto(drawSurface,
readImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone),
blurMatrix),
- readImage->width() / static_cast<float>(drawSurface->width()), radius, alpha);
+ radius, alpha, blurEffect);
}
void KawaseBlurDualFilter::blurInto(const sk_sp<SkSurface>& drawSurface, sk_sp<SkShader> input,
- const float inverseScale, const float radius,
- const float alpha) const {
+ const float radius, const float alpha,
+ const sk_sp<SkRuntimeEffect>& blurEffect) const {
SkPaint paint;
if (radius == 0) {
paint.setShader(std::move(input));
paint.setAlphaf(alpha);
} else {
- SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
+ SkRuntimeShaderBuilder blurBuilder(blurEffect);
blurBuilder.child("child") = std::move(input);
+ if (blurEffect == mLowSampleBlurEffect) {
+ blurBuilder.uniform("in_crossFade") = alpha;
+ blurBuilder.uniform("in_weightedCrossFade") = alpha * 0.2f;
+ }
blurBuilder.uniform("in_blurOffset") = radius;
- blurBuilder.uniform("in_crossFade") = alpha;
paint.setShader(blurBuilder.makeShader(nullptr));
}
paint.setBlendMode(alpha == 1.0f ? SkBlendMode::kSrc : SkBlendMode::kSrcOver);
@@ -163,16 +194,19 @@
input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone),
blurMatrix);
- blurInto(surfaces[0], std::move(sourceShader), kInputScale, kWeights[0] * step, 1.0f);
+ blurInto(surfaces[0], std::move(sourceShader), kWeights[0] * step, 1.0f,
+ mLowSampleBlurEffect);
}
// Next the remaining downscale blur passes.
for (int i = 0; i < filterPasses; i++) {
- blurInto(surfaces[i + 1], surfaces[i]->makeTemporaryImage(), kWeights[1 + i] * step, 1.0f);
+ // Blur with the higher sample effect into the smaller buffers, for better visual quality.
+ blurInto(surfaces[i + 1], surfaces[i]->makeTemporaryImage(), kWeights[1 + i] * step, 1.0f,
+ i == 0 ? mLowSampleBlurEffect : mHighSampleBlurEffect);
}
// Finally blur+upscale back to our original size.
for (int i = filterPasses - 1; i >= 0; i--) {
blurInto(surfaces[i], surfaces[i + 1]->makeTemporaryImage(), kWeights[4 - i] * step,
- std::min(1.0f, filterDepth - i));
+ std::min(1.0f, filterDepth - i), mLowSampleBlurEffect);
}
return surfaces[0]->makeTemporaryImage();
}
diff --git a/libs/renderengine/skia/filters/KawaseBlurDualFilter.h b/libs/renderengine/skia/filters/KawaseBlurDualFilter.h
index 6f4adbf..5efda35 100644
--- a/libs/renderengine/skia/filters/KawaseBlurDualFilter.h
+++ b/libs/renderengine/skia/filters/KawaseBlurDualFilter.h
@@ -41,13 +41,14 @@
const sk_sp<SkImage> blurInput, const SkRect& blurRect) const override;
private:
- sk_sp<SkRuntimeEffect> mBlurEffect;
+ sk_sp<SkRuntimeEffect> mLowSampleBlurEffect;
+ sk_sp<SkRuntimeEffect> mHighSampleBlurEffect;
void blurInto(const sk_sp<SkSurface>& drawSurface, const sk_sp<SkImage>& readImage,
- const float radius, const float alpha) const;
+ const float radius, const float alpha, const sk_sp<SkRuntimeEffect>&) const;
void blurInto(const sk_sp<SkSurface>& drawSurface, const sk_sp<SkShader> input,
- const float inverseScale, const float radius, const float alpha) const;
+ const float radius, const float alpha, const sk_sp<SkRuntimeEffect>&) const;
};
} // namespace skia
diff --git a/libs/ui/DisplayIdentification.cpp b/libs/ui/DisplayIdentification.cpp
index b7ef9b3..78e84fc 100644
--- a/libs/ui/DisplayIdentification.cpp
+++ b/libs/ui/DisplayIdentification.cpp
@@ -444,7 +444,7 @@
(edid.hashedBlockZeroSerialNumberOpt.value_or(0) >> 11) ^
(edid.hashedDescriptorBlockSerialNumberOpt.value_or(0) << 23);
- return PhysicalDisplayId::fromEdidHash(id);
+ return PhysicalDisplayId::fromValue(id);
}
} // namespace android
diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h
index 13ed754..937e3f1 100644
--- a/libs/ui/include/ui/DisplayId.h
+++ b/libs/ui/include/ui/DisplayId.h
@@ -30,27 +30,16 @@
// Flag indicating that the display is virtual.
static constexpr uint64_t FLAG_VIRTUAL = 1ULL << 63;
- // TODO(b/162612135) Remove default constructor
+ // TODO: b/162612135 - Remove default constructor.
DisplayId() = default;
constexpr DisplayId(const DisplayId&) = default;
DisplayId& operator=(const DisplayId&) = default;
+ static constexpr DisplayId fromValue(uint64_t value) { return DisplayId(value); }
constexpr bool isVirtual() const { return value & FLAG_VIRTUAL; }
uint64_t value;
- // For deserialization.
- static constexpr std::optional<DisplayId> fromValue(uint64_t);
-
- // As above, but also upcast to Id.
- template <typename Id>
- static constexpr std::optional<Id> fromValue(uint64_t value) {
- if (const auto id = Id::tryCast(DisplayId(value))) {
- return id;
- }
- return {};
- }
-
protected:
explicit constexpr DisplayId(uint64_t id) : value(id) {}
};
@@ -74,6 +63,9 @@
// DisplayId of a physical display, such as the internal display or externally connected display.
struct PhysicalDisplayId : DisplayId {
+ // TODO: b/162612135 - Remove default constructor.
+ PhysicalDisplayId() = default;
+
static constexpr ftl::Optional<PhysicalDisplayId> tryCast(DisplayId id) {
if (id.isVirtual()) {
return std::nullopt;
@@ -87,11 +79,6 @@
return PhysicalDisplayId(FLAG_STABLE, port, manufacturerId, modelHash);
}
- // Returns a stable and consistent ID based exclusively on EDID information.
- static constexpr PhysicalDisplayId fromEdidHash(uint64_t hashedEdid) {
- return PhysicalDisplayId(hashedEdid);
- }
-
// Returns an unstable ID. If EDID is available using "fromEdid" is preferred.
static constexpr PhysicalDisplayId fromPort(uint8_t port) {
constexpr uint16_t kManufacturerId = 0;
@@ -99,8 +86,9 @@
return PhysicalDisplayId(0, port, kManufacturerId, kModelHash);
}
- // TODO(b/162612135) Remove default constructor
- PhysicalDisplayId() = default;
+ static constexpr PhysicalDisplayId fromValue(uint64_t value) {
+ return PhysicalDisplayId(value);
+ }
constexpr uint8_t getPort() const { return static_cast<uint8_t>(value); }
@@ -131,8 +119,15 @@
return std::nullopt;
}
+ static constexpr VirtualDisplayId fromValue(uint64_t value) {
+ return VirtualDisplayId(SkipVirtualFlag{}, value);
+ }
+
protected:
+ struct SkipVirtualFlag {};
+ constexpr VirtualDisplayId(SkipVirtualFlag, uint64_t value) : DisplayId(value) {}
explicit constexpr VirtualDisplayId(uint64_t value) : DisplayId(FLAG_VIRTUAL | value) {}
+
explicit constexpr VirtualDisplayId(DisplayId other) : DisplayId(other) {}
};
@@ -146,8 +141,12 @@
return std::nullopt;
}
+ static constexpr HalVirtualDisplayId fromValue(uint64_t value) {
+ return HalVirtualDisplayId(SkipVirtualFlag{}, value);
+ }
+
private:
- explicit constexpr HalVirtualDisplayId(DisplayId other) : VirtualDisplayId(other) {}
+ using VirtualDisplayId::VirtualDisplayId;
};
struct GpuVirtualDisplayId : VirtualDisplayId {
@@ -160,8 +159,12 @@
return std::nullopt;
}
+ static constexpr GpuVirtualDisplayId fromValue(uint64_t value) {
+ return GpuVirtualDisplayId(SkipVirtualFlag{}, value);
+ }
+
private:
- explicit constexpr GpuVirtualDisplayId(DisplayId other) : VirtualDisplayId(other) {}
+ using VirtualDisplayId::VirtualDisplayId;
};
// HalDisplayId is the ID of a display which is managed by HWC.
@@ -177,20 +180,13 @@
return HalDisplayId(id);
}
+ static constexpr HalDisplayId fromValue(uint64_t value) { return HalDisplayId(value); }
+
private:
+ using DisplayId::DisplayId;
explicit constexpr HalDisplayId(DisplayId other) : DisplayId(other) {}
};
-constexpr std::optional<DisplayId> DisplayId::fromValue(uint64_t value) {
- if (const auto id = fromValue<PhysicalDisplayId>(value)) {
- return id;
- }
- if (const auto id = fromValue<VirtualDisplayId>(value)) {
- return id;
- }
- return {};
-}
-
static_assert(sizeof(DisplayId) == sizeof(uint64_t));
static_assert(sizeof(HalDisplayId) == sizeof(uint64_t));
static_assert(sizeof(VirtualDisplayId) == sizeof(uint64_t));
diff --git a/libs/ui/include/ui/ShadowSettings.h b/libs/ui/include/ui/ShadowSettings.h
index 06be6db..c0b83b8 100644
--- a/libs/ui/include/ui/ShadowSettings.h
+++ b/libs/ui/include/ui/ShadowSettings.h
@@ -46,9 +46,6 @@
// Length of the cast shadow. If length is <= 0.f no shadows will be drawn.
float length = 0.f;
- // Length of the cast shadow that is drawn by the client.
- float clientDrawnLength = 0.f;
-
// If true fill in the casting layer is translucent and the shadow needs to fill the bounds.
// Otherwise the shadow will only be drawn around the edges of the casting layer.
bool casterIsTranslucent = false;
@@ -58,7 +55,6 @@
return lhs.boundaries == rhs.boundaries && lhs.ambientColor == rhs.ambientColor &&
lhs.spotColor == rhs.spotColor && lhs.lightPos == rhs.lightPos &&
lhs.lightRadius == rhs.lightRadius && lhs.length == rhs.length &&
- lhs.clientDrawnLength == rhs.clientDrawnLength &&
lhs.casterIsTranslucent == rhs.casterIsTranslucent;
}
diff --git a/libs/ui/tests/DisplayId_test.cpp b/libs/ui/tests/DisplayId_test.cpp
index 090d2ee..209acba 100644
--- a/libs/ui/tests/DisplayId_test.cpp
+++ b/libs/ui/tests/DisplayId_test.cpp
@@ -33,7 +33,7 @@
EXPECT_TRUE(HalDisplayId::tryCast(id));
EXPECT_EQ(id, DisplayId::fromValue(id.value));
- EXPECT_EQ(id, DisplayId::fromValue<PhysicalDisplayId>(id.value));
+ EXPECT_EQ(id, PhysicalDisplayId::fromValue(id.value));
}
TEST(DisplayIdTest, createPhysicalIdFromPort) {
@@ -47,7 +47,7 @@
EXPECT_TRUE(HalDisplayId::tryCast(id));
EXPECT_EQ(id, DisplayId::fromValue(id.value));
- EXPECT_EQ(id, DisplayId::fromValue<PhysicalDisplayId>(id.value));
+ EXPECT_EQ(id, PhysicalDisplayId::fromValue(id.value));
}
TEST(DisplayIdTest, createGpuVirtualId) {
@@ -59,7 +59,7 @@
EXPECT_FALSE(HalDisplayId::tryCast(id));
EXPECT_EQ(id, DisplayId::fromValue(id.value));
- EXPECT_EQ(id, DisplayId::fromValue<GpuVirtualDisplayId>(id.value));
+ EXPECT_EQ(id, GpuVirtualDisplayId::fromValue(id.value));
}
TEST(DisplayIdTest, createVirtualIdFromGpuVirtualId) {
@@ -83,7 +83,7 @@
EXPECT_TRUE(HalDisplayId::tryCast(id));
EXPECT_EQ(id, DisplayId::fromValue(id.value));
- EXPECT_EQ(id, DisplayId::fromValue<HalVirtualDisplayId>(id.value));
+ EXPECT_EQ(id, HalVirtualDisplayId::fromValue(id.value));
}
TEST(DisplayIdTest, createVirtualIdFromHalVirtualId) {
diff --git a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
index 7c255ed..5ba72af 100644
--- a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
@@ -113,7 +113,7 @@
if (producer == NULL)
goto not_valid_surface;
- window = new android::Surface(producer, true);
+ window = android::sp<android::Surface>::make(producer, true);
if (window == NULL)
goto not_valid_surface;
diff --git a/services/automotive/display/AutomotiveDisplayProxyService.cpp b/services/automotive/display/AutomotiveDisplayProxyService.cpp
index d205231..afa6233 100644
--- a/services/automotive/display/AutomotiveDisplayProxyService.cpp
+++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp
@@ -34,10 +34,8 @@
sp<IBinder> displayToken = nullptr;
sp<SurfaceControl> surfaceControl = nullptr;
if (it == mDisplays.end()) {
- if (const auto displayId = DisplayId::fromValue<PhysicalDisplayId>(id)) {
- displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
- }
-
+ displayToken =
+ SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId::fromValue(id));
if (displayToken == nullptr) {
ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id);
return nullptr;
@@ -160,11 +158,8 @@
HwDisplayConfig activeConfig;
HwDisplayState activeState;
- sp<IBinder> displayToken;
- if (const auto displayId = DisplayId::fromValue<PhysicalDisplayId>(id)) {
- displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
- }
-
+ sp<IBinder> displayToken =
+ SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId::fromValue(id));
if (displayToken == nullptr) {
ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id);
} else {
@@ -197,4 +192,3 @@
} // namespace automotive
} // namespace frameworks
} // namespace android
-
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index ba8c814..05602ef 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -4554,8 +4554,9 @@
args.displayId.toString().c_str()));
Result<void> result =
it->second.processMovement(args.deviceId, args.source, args.action,
- args.getPointerCount(), args.pointerProperties.data(),
- args.pointerCoords.data(), args.flags);
+ args.actionButton, args.getPointerCount(),
+ args.pointerProperties.data(), args.pointerCoords.data(),
+ args.flags, args.buttonState);
if (!result.ok()) {
LOG(FATAL) << "Bad stream: " << result.error() << " caused by " << args.dump();
}
@@ -4751,9 +4752,10 @@
Result<void> result =
verifier.processMovement(deviceId, motionEvent.getSource(), motionEvent.getAction(),
- motionEvent.getPointerCount(),
+ motionEvent.getActionButton(), motionEvent.getPointerCount(),
motionEvent.getPointerProperties(),
- motionEvent.getSamplePointerCoords(), flags);
+ motionEvent.getSamplePointerCoords(), flags,
+ motionEvent.getButtonState());
if (!result.ok()) {
logDispatchStateLocked();
LOG(ERROR) << "Inconsistent event: " << motionEvent << ", reason: " << result.error();
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index 301632f..f2b2b6f 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -115,6 +115,7 @@
ui::Rotation mOrientation{ui::ROTATION_0};
FloatRect mBoundsInLogicalDisplay{};
+ // The button state as of the last sync.
int32_t mButtonState;
nsecs_t mDownTime;
nsecs_t mLastEventTime;
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index fd9884b..914f5ab 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -1721,15 +1721,16 @@
mParamContinueGesture(std::get<1>(GetParam())),
mParamEndGesture(std::get<2>(GetParam())),
mDeviceContext(*mDevice, EVENTHUB_ID),
- mConverter(*mReader->getContext(), mDeviceContext, DEVICE_ID),
- mVerifier("Test verifier") {
+ mConverter(*mReader->getContext(), mDeviceContext, DEVICE_ID) {
mConverter.setDisplayId(ui::LogicalDisplayId::DEFAULT);
+ input_flags::enable_button_state_verification(true);
+ mVerifier = std::make_unique<InputVerifier>("Test verifier");
}
base::Result<void> processMotionArgs(NotifyMotionArgs arg) {
- return mVerifier.processMovement(arg.deviceId, arg.source, arg.action,
- arg.getPointerCount(), arg.pointerProperties.data(),
- arg.pointerCoords.data(), arg.flags);
+ return mVerifier->processMovement(arg.deviceId, arg.source, arg.action, arg.actionButton,
+ arg.getPointerCount(), arg.pointerProperties.data(),
+ arg.pointerCoords.data(), arg.flags, arg.buttonState);
}
void verifyArgsFromGesture(const Gesture& gesture, size_t gestureIndex) {
@@ -1755,7 +1756,7 @@
InputDeviceContext mDeviceContext;
GestureConverter mConverter;
- InputVerifier mVerifier;
+ std::unique_ptr<InputVerifier> mVerifier;
};
TEST_P(GestureConverterConsistencyTest, ButtonChangesDuringGesture) {
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c0e2060..7cc4ff7 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -12405,43 +12405,69 @@
}
void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
+ bool consumeButtonPress = false;
switch (fromSource) {
- case AINPUT_SOURCE_TOUCHSCREEN:
+ case AINPUT_SOURCE_TOUCHSCREEN: {
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
ui::LogicalDisplayId::DEFAULT, {50, 50}))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
break;
- case AINPUT_SOURCE_STYLUS:
+ }
+ case AINPUT_SOURCE_STYLUS: {
+ PointerBuilder pointer = PointerBuilder(0, ToolType::STYLUS).x(50).y(50);
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionEvent(*mDispatcher,
MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
AINPUT_SOURCE_STYLUS)
.buttonState(
AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
- .pointer(PointerBuilder(0, ToolType::STYLUS)
- .x(50)
- .y(50))
+ .pointer(pointer)
.build()));
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(*mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ AINPUT_SOURCE_STYLUS)
+ .actionButton(
+ AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
+ .buttonState(
+ AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
+ .pointer(pointer)
+ .build()));
+ consumeButtonPress = true;
break;
- case AINPUT_SOURCE_MOUSE:
+ }
+ case AINPUT_SOURCE_MOUSE: {
+ PointerBuilder pointer =
+ PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50);
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionEvent(*mDispatcher,
MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
AINPUT_SOURCE_MOUSE)
.buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
- .pointer(PointerBuilder(MOUSE_POINTER_ID,
- ToolType::MOUSE)
- .x(50)
- .y(50))
+ .pointer(pointer)
.build()));
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(*mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ AINPUT_SOURCE_MOUSE)
+ .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(pointer)
+ .build()));
+ consumeButtonPress = true;
break;
- default:
+ }
+ default: {
FAIL() << "Source " << fromSource << " doesn't support drag and drop";
+ }
}
// Window should receive motion event.
mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
+ if (consumeButtonPress) {
+ mWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
+ }
// Spy window should also receive motion event
mSpyWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
}
@@ -12641,6 +12667,16 @@
// Move to another window and release button, expect to drop item.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionEvent(*mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
+ AINPUT_SOURCE_STYLUS)
+ .actionButton(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
+ .buttonState(0)
+ .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
+ .build()))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(*mDispatcher,
MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
.buttonState(0)
.pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50))
@@ -12882,6 +12918,18 @@
// drop to another window.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionEvent(*mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE,
+ AINPUT_SOURCE_MOUSE)
+ .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
+ .buttonState(0)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
+ .x(150)
+ .y(50))
+ .build()))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE));
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(*mDispatcher,
MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
.buttonState(0)
.pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
diff --git a/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp
index 31db2fe..abce931 100644
--- a/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp
@@ -48,9 +48,9 @@
auto [it, _] = mVerifiers.emplace(args.displayId, "Fuzz Verifier");
InputVerifier& verifier = it->second;
const Result<void> result =
- verifier.processMovement(args.deviceId, args.source, args.action,
+ verifier.processMovement(args.deviceId, args.source, args.action, args.actionButton,
args.getPointerCount(), args.pointerProperties.data(),
- args.pointerCoords.data(), args.flags);
+ args.pointerCoords.data(), args.flags, args.buttonState);
if (result.ok()) {
return args;
}
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 77bf145..6088e25 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -110,8 +110,8 @@
LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this),
"MirrorRoot-" + std::to_string(displayId), 0 /* flags */,
gui::LayerMetadata());
- std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId));
- status_t status = mFlinger->mirrorDisplay(*id, args, *outResult);
+ const DisplayId id = DisplayId::fromValue(static_cast<uint64_t>(displayId));
+ status_t status = mFlinger->mirrorDisplay(id, args, *outResult);
return binderStatusFromStatusT(status);
}
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index e876693..780758e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -19,6 +19,7 @@
#include <optional>
#include <ostream>
#include <unordered_set>
+#include "aidl/android/hardware/graphics/composer3/Composition.h"
#include "ui/LayerStack.h"
// TODO(b/129481165): remove the #pragma below and fix conversion issues
@@ -36,10 +37,6 @@
#include <utils/RefBase.h>
#include <utils/Timers.h>
-namespace aidl::android::hardware::graphics::composer3 {
-enum class Composition;
-}
-
namespace android {
class Fence;
@@ -182,10 +179,27 @@
// Whether the layer should be rendered with rounded corners.
virtual bool hasRoundedCorners() const = 0;
virtual void setWasClientComposed(const sp<Fence>&) {}
- virtual void setHwcCompositionType(
- aidl::android::hardware::graphics::composer3::Composition) = 0;
- virtual aidl::android::hardware::graphics::composer3::Composition getHwcCompositionType()
- const = 0;
+
+ // These fields are all copied from the last written HWC state.
+ // This state is only used for debugging purposes.
+ struct HwcLayerDebugState {
+ aidl::android::hardware::graphics::composer3::Composition lastCompositionType =
+ aidl::android::hardware::graphics::composer3::Composition::INVALID;
+ // Corresponds to passing an alpha of 0 to HWC2::Layer::setPlaneAlpha.
+ bool wasSkipped = false;
+
+ // Indicates whether the compositionengine::OutputLayer had properties overwritten.
+ // Not directly passed to HWC.
+ bool wasOverridden = false;
+
+ // Corresponds to the GraphicBuffer ID of the buffer passed to HWC2::Layer::setBuffer.
+ // This buffer corresponds to a CachedSet that the LayerFE was flattened to.
+ uint64_t overrideBufferId = 0;
+ };
+
+ // Used for debugging purposes, e.g. perfetto tracing, dumpsys.
+ virtual void setLastHwcState(const LayerFE::HwcLayerDebugState &hwcState) = 0;
+ virtual const HwcLayerDebugState &getLastHwcState() const = 0;
virtual const gui::LayerMetadata* getMetadata() const = 0;
virtual const gui::LayerMetadata* getRelativeMetadata() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 7744b8b..d2a5a20 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -59,9 +59,9 @@
MOCK_CONST_METHOD0(getMetadata, gui::LayerMetadata*());
MOCK_CONST_METHOD0(getRelativeMetadata, gui::LayerMetadata*());
MOCK_METHOD0(onPictureProfileCommitted, void());
- MOCK_METHOD(void, setHwcCompositionType,
- (aidl::android::hardware::graphics::composer3::Composition), (override));
- MOCK_METHOD(aidl::android::hardware::graphics::composer3::Composition, getHwcCompositionType,
+ MOCK_METHOD(void, setLastHwcState,
+ (const HwcLayerDebugState&), (override));
+ MOCK_METHOD(const HwcLayerDebugState&, getLastHwcState,
(), (const, override));
};
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 9b66f01..9d67122 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -502,6 +502,15 @@
editState().hwc->stateOverridden = isOverridden;
editState().hwc->layerSkipped = skipLayer;
+
+
+ // Save the final HWC state for debugging purposes, e.g. perfetto tracing, dumpsys.
+ getLayerFE().setLastHwcState({.lastCompositionType = editState().hwc->hwcCompositionType,
+ .wasSkipped = skipLayer,
+ .wasOverridden = isOverridden,
+ .overrideBufferId = editState().overrideInfo.buffer
+ ? editState().overrideInfo.buffer.get()->getId()
+ : 0});
}
void OutputLayer::writeOutputDependentGeometryStateToHWC(HWC2::Layer* hwcLayer,
@@ -867,7 +876,6 @@
if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType ||
(outputDependentState.hwc->layerSkipped && !skipLayer)) {
outputDependentState.hwc->hwcCompositionType = requestedCompositionType;
- getLayerFE().setHwcCompositionType(requestedCompositionType);
if (auto error = hwcLayer->setCompositionType(requestedCompositionType);
error != hal::Error::NONE) {
@@ -965,7 +973,13 @@
}
hwcState.hwcCompositionType = compositionType;
- getLayerFE().setHwcCompositionType(compositionType);
+
+ getLayerFE().setLastHwcState({.lastCompositionType = hwcState.hwcCompositionType,
+ .wasSkipped = hwcState.layerSkipped,
+ .wasOverridden = hwcState.stateOverridden,
+ .overrideBufferId = state.overrideInfo.buffer
+ ? state.overrideInfo.buffer.get()->getId()
+ : 0});
}
void OutputLayer::prepareForDeviceLayerRequests() {
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 523ef7b..839bd79 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -403,11 +403,8 @@
if (forceUpdate || requested.what & layer_state_t::eSidebandStreamChanged) {
sidebandStream = requested.sidebandStream;
}
- if (forceUpdate || requested.what & layer_state_t::eShadowRadiusChanged ||
- requested.what & layer_state_t::eClientDrawnShadowsChanged) {
- shadowSettings.length =
- requested.clientDrawnShadowRadius > 0 ? 0.f : requested.shadowRadius;
- shadowSettings.clientDrawnLength = requested.clientDrawnShadowRadius;
+ if (forceUpdate || requested.what & layer_state_t::eShadowRadiusChanged) {
+ shadowSettings.length = requested.shadowRadius;
}
if (forceUpdate || requested.what & layer_state_t::eFrameRateSelectionPriority) {
@@ -537,12 +534,13 @@
}
}
-char LayerSnapshot::classifyCompositionForDebug(Composition compositionType) const {
+char LayerSnapshot::classifyCompositionForDebug(
+ const compositionengine::LayerFE::HwcLayerDebugState& hwcState) const {
if (!isVisible) {
return '.';
}
- switch (compositionType) {
+ switch (hwcState.lastCompositionType) {
case Composition::INVALID:
return 'i';
case Composition::SOLID_COLOR:
@@ -561,21 +559,21 @@
}
char code = '.'; // Default to invisible
- if (hasBufferOrSidebandStream()) {
- code = 'b';
- } else if (fillsColor()) {
- code = 'c'; // Solid color
- } else if (hasBlur()) {
+ if (hasBlur()) {
code = 'l'; // Blur
} else if (hasProtectedContent) {
code = 'p'; // Protected content
- } else if (drawShadows()) {
- code = 's'; // Shadow
} else if (roundedCorner.hasRoundedCorners()) {
code = 'r'; // Rounded corners
+ } else if (drawShadows()) {
+ code = 's'; // Shadow
+ } else if (fillsColor()) {
+ code = 'c'; // Solid color
+ } else if (hasBufferOrSidebandStream()) {
+ code = 'b';
}
- if (compositionType == Composition::CLIENT) {
+ if (hwcState.lastCompositionType == Composition::CLIENT) {
return static_cast<char>(std::toupper(code));
} else {
return code;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index 04b9f3b..69120bd 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -24,6 +24,7 @@
#include "RequestedLayerState.h"
#include "Scheduler/LayerInfo.h"
#include "android-base/stringprintf.h"
+#include "compositionengine/LayerFE.h"
namespace android::surfaceflinger::frontend {
@@ -163,7 +164,7 @@
// Returns a char summarizing the composition request
// This function tries to maintain parity with planner::Plan chars.
char classifyCompositionForDebug(
- aidl::android::hardware::graphics::composer3::Composition compositionType) const;
+ const compositionengine::LayerFE::HwcLayerDebugState& hwcState) const;
};
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 1d53e71..58c235e 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -108,7 +108,6 @@
surfaceDamageRegion = Region::INVALID_REGION;
cornerRadius = 0.0f;
clientDrawnCornerRadius = 0.0f;
- clientDrawnShadowRadius = 0.0f;
backgroundBlurRadius = 0;
api = -1;
hasColorTransform = false;
@@ -355,11 +354,6 @@
clientDrawnCornerRadius = clientState.clientDrawnCornerRadius;
changes |= RequestedLayerState::Changes::Geometry;
}
-
- if (clientState.what & layer_state_t::eClientDrawnShadowsChanged) {
- clientDrawnShadowRadius = clientState.clientDrawnShadowRadius;
- changes |= RequestedLayerState::Changes::Geometry;
- }
}
ui::Size RequestedLayerState::getUnrotatedBufferSize(uint32_t displayRotationFlags) const {
@@ -646,7 +640,6 @@
layer_state_t::eColorTransformChanged | layer_state_t::eBackgroundColorChanged |
layer_state_t::eMatrixChanged | layer_state_t::eCornerRadiusChanged |
layer_state_t::eClientDrawnCornerRadiusChanged |
- layer_state_t::eClientDrawnShadowsChanged |
layer_state_t::eBackgroundBlurRadiusChanged | layer_state_t::eBufferTransformChanged |
layer_state_t::eTransformToDisplayInverseChanged | layer_state_t::eCropChanged |
layer_state_t::eDataspaceChanged | layer_state_t::eHdrMetadataChanged |
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
index 725a782..b619268 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -428,13 +428,12 @@
return mReleaseFencePromiseStatus;
}
-void LayerFE::setHwcCompositionType(
- aidl::android::hardware::graphics::composer3::Composition type) {
- mLastHwcCompositionType = type;
+void LayerFE::setLastHwcState(const LayerFE::HwcLayerDebugState &state) {
+ mLastHwcState = state;
}
-aidl::android::hardware::graphics::composer3::Composition LayerFE::getHwcCompositionType() const {
- return mLastHwcCompositionType;
-}
+const LayerFE::HwcLayerDebugState& LayerFE::getLastHwcState() const {
+ return mLastHwcState;
+};
} // namespace android
diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h
index 64ec278..a537456 100644
--- a/services/surfaceflinger/LayerFE.h
+++ b/services/surfaceflinger/LayerFE.h
@@ -59,9 +59,10 @@
void setReleaseFence(const FenceResult& releaseFence) override;
LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() override;
void onPictureProfileCommitted() override;
- void setHwcCompositionType(aidl::android::hardware::graphics::composer3::Composition) override;
- aidl::android::hardware::graphics::composer3::Composition getHwcCompositionType()
- const override;
+
+ // Used for debugging purposes, e.g. perfetto tracing, dumpsys.
+ void setLastHwcState(const HwcLayerDebugState &state) override;
+ const HwcLayerDebugState &getLastHwcState() const override;
std::unique_ptr<surfaceflinger::frontend::LayerSnapshot> mSnapshot;
@@ -93,8 +94,7 @@
std::string mName;
std::promise<FenceResult> mReleaseFence;
ReleaseFencePromiseStatus mReleaseFencePromiseStatus = ReleaseFencePromiseStatus::UNINITIALIZED;
- aidl::android::hardware::graphics::composer3::Composition mLastHwcCompositionType =
- aidl::android::hardware::graphics::composer3::Composition::INVALID;
+ HwcLayerDebugState mLastHwcState;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1dc7b2e..1163390 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1163,8 +1163,8 @@
}
Mutex::Autolock lock(mStateLock);
- const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
- const auto displayOpt = mPhysicalDisplays.get(*id).and_then(getDisplayDeviceAndSnapshot());
+ const PhysicalDisplayId id = PhysicalDisplayId::fromValue(static_cast<uint64_t>(displayId));
+ const auto displayOpt = mPhysicalDisplays.get(id).and_then(getDisplayDeviceAndSnapshot());
if (!displayOpt) {
return NAME_NOT_FOUND;
@@ -1286,9 +1286,9 @@
Mutex::Autolock lock(mStateLock);
- const auto id_ =
- DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(physicalDisplayId));
- const auto displayOpt = mPhysicalDisplays.get(*id_).and_then(getDisplayDeviceAndSnapshot());
+ const PhysicalDisplayId id =
+ PhysicalDisplayId::fromValue(static_cast<uint64_t>(physicalDisplayId));
+ const auto displayOpt = mPhysicalDisplays.get(id).and_then(getDisplayDeviceAndSnapshot());
if (!displayOpt) {
return NAME_NOT_FOUND;
@@ -2977,6 +2977,8 @@
int index = 0;
ftl::StaticVector<char, WorkloadTracer::COMPOSITION_SUMMARY_SIZE> compositionSummary;
auto lastLayerStack = ui::INVALID_LAYER_STACK;
+
+ uint64_t prevOverrideBufferId = 0;
for (auto& [layer, layerFE] : layers) {
CompositionResult compositionResult{layerFE->stealCompositionResult()};
if (lastLayerStack != layerFE->mSnapshot->outputFilter.layerStack) {
@@ -2986,8 +2988,37 @@
}
lastLayerStack = layerFE->mSnapshot->outputFilter.layerStack;
}
+
+ // If there are N layers in a cached set they should all share the same buffer id.
+ // The first layer in the cached set will be not skipped and layers 1..N-1 will be skipped.
+ // We expect all layers in the cached set to be marked as composited by HWC.
+ // Here is a made up example of how it is visualized
+ //
+ // [b:rrc][s:cc]
+ //
+ // This should be interpreted to mean that there are 2 cached sets.
+ // So there are only 2 non skipped layers -- b and s.
+ // The layers rrc and cc are flattened into layers b and s respectively.
+ const LayerFE::HwcLayerDebugState &hwcState = layerFE->getLastHwcState();
+ if (hwcState.overrideBufferId != prevOverrideBufferId) {
+ // End the existing run.
+ if (prevOverrideBufferId) {
+ compositionSummary.push_back(']');
+ }
+ // Start a new run.
+ if (hwcState.overrideBufferId) {
+ compositionSummary.push_back('[');
+ }
+ }
+
compositionSummary.push_back(
- layerFE->mSnapshot->classifyCompositionForDebug(layerFE->getHwcCompositionType()));
+ layerFE->mSnapshot->classifyCompositionForDebug(hwcState));
+
+ if (hwcState.overrideBufferId && !hwcState.wasSkipped) {
+ compositionSummary.push_back(':');
+ }
+ prevOverrideBufferId = hwcState.overrideBufferId;
+
if (layerFE->mSnapshot->hasEffect()) {
compositedWorkload |= adpf::Workload::EFFECTS;
}
@@ -2999,6 +3030,10 @@
mActivePictureTracker.onLayerComposed(*layer, *layerFE, compositionResult);
}
}
+ // End the last run.
+ if (prevOverrideBufferId) {
+ compositionSummary.push_back(']');
+ }
// Concisely describe the layers composited this frame using single chars. GPU composited layers
// are uppercase, DPU composited are lowercase. Special chars denote effects (blur, shadow,
@@ -6731,8 +6766,9 @@
return getDefaultDisplayDevice()->getDisplayToken().promote();
}
- if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(value)) {
- return getPhysicalDisplayToken(*id);
+ if (const auto token =
+ getPhysicalDisplayToken(PhysicalDisplayId::fromValue(value))) {
+ return token;
}
ALOGE("Invalid physical display ID");
@@ -6830,10 +6866,10 @@
case 1040: {
auto future = mScheduler->schedule([&] {
n = data.readInt32();
- std::optional<PhysicalDisplayId> inputId = std::nullopt;
+ PhysicalDisplayId inputId;
if (uint64_t inputDisplayId; data.readUint64(&inputDisplayId) == NO_ERROR) {
- inputId = DisplayId::fromValue<PhysicalDisplayId>(inputDisplayId);
- if (!inputId || getPhysicalDisplayToken(*inputId)) {
+ inputId = PhysicalDisplayId::fromValue(inputDisplayId);
+ if (!getPhysicalDisplayToken(inputId)) {
ALOGE("No display with id: %" PRIu64, inputDisplayId);
return NAME_NOT_FOUND;
}
@@ -6842,7 +6878,7 @@
Mutex::Autolock lock(mStateLock);
mLayerCachingEnabled = n != 0;
for (const auto& [_, display] : mDisplays) {
- if (!inputId || *inputId == display->getPhysicalId()) {
+ if (inputId == display->getPhysicalId()) {
display->enableLayerCaching(mLayerCachingEnabled);
}
}
@@ -6925,11 +6961,10 @@
int64_t arg1 = data.readInt64();
int64_t arg2 = data.readInt64();
// Enable mirroring for one display
- const auto display1id = DisplayId::fromValue(arg1);
auto mirrorRoot = SurfaceComposerClient::getDefault()->mirrorDisplay(
- display1id.value());
- auto id2 = DisplayId::fromValue<PhysicalDisplayId>(arg2);
- const auto token2 = getPhysicalDisplayToken(*id2);
+ DisplayId::fromValue(arg1));
+ const auto token2 =
+ getPhysicalDisplayToken(PhysicalDisplayId::fromValue(arg2));
ui::LayerStack layerStack;
{
Mutex::Autolock lock(mStateLock);
@@ -8714,8 +8749,8 @@
if (status != OK) {
return binderStatusFromStatusT(status);
}
- const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
- *outDisplay = mFlinger->getPhysicalDisplayToken(*id);
+ const PhysicalDisplayId id = PhysicalDisplayId::fromValue(static_cast<uint64_t>(displayId));
+ *outDisplay = mFlinger->getPhysicalDisplayToken(id);
return binder::Status::ok();
}
diff --git a/services/surfaceflinger/common/include/common/WorkloadTracer.h b/services/surfaceflinger/common/include/common/WorkloadTracer.h
index 39b6fa1..c4074f7 100644
--- a/services/surfaceflinger/common/include/common/WorkloadTracer.h
+++ b/services/surfaceflinger/common/include/common/WorkloadTracer.h
@@ -23,7 +23,7 @@
static constexpr int32_t COMPOSITION_TRACE_COOKIE = 1;
static constexpr int32_t POST_COMPOSITION_TRACE_COOKIE = 2;
-static constexpr size_t COMPOSITION_SUMMARY_SIZE = 20;
+static constexpr size_t COMPOSITION_SUMMARY_SIZE = 64;
static constexpr const char* TRACK_NAME = "CriticalWorkload";
} // namespace android::WorkloadTracer
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
index ee5d919..7910e77 100644
--- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
+++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
@@ -497,17 +497,6 @@
mLifecycleManager.applyTransactions(transactions);
}
- void setClientDrawnShadowRadius(uint32_t id, float clientDrawnShadowRadius) {
- std::vector<QueuedTransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eClientDrawnShadowsChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.clientDrawnShadowRadius = clientDrawnShadowRadius;
- mLifecycleManager.applyTransactions(transactions);
- }
-
void setShadowRadius(uint32_t id, float shadowRadius) {
std::vector<QueuedTransactionState> transactions;
transactions.emplace_back();
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 3fead93..81bfc97 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -193,7 +193,7 @@
}
};
-template <uint64_t displayId>
+template <VirtualDisplayId::BaseId displayId>
struct DisplayIdGetter<HalVirtualDisplayIdType<displayId>> {
static HalVirtualDisplayId get() { return HalVirtualDisplayId(displayId); }
};
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 453c053..7aad84b 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -1505,14 +1505,6 @@
EXPECT_EQ(getSnapshot({.id = 111})->roundedCorner.radius.x, RADIUS);
}
-TEST_F(LayerSnapshotTest, ignoreShadows) {
- static constexpr float SHADOW_RADIUS = 123.f;
- setClientDrawnShadowRadius(1, SHADOW_RADIUS);
- setShadowRadius(1, SHADOW_RADIUS);
- UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
- EXPECT_EQ(getSnapshot({.id = 1})->shadowSettings.length, 0.f);
-}
-
TEST_F(LayerSnapshotTest, setShadowRadius) {
static constexpr float SHADOW_RADIUS = 123.f;
setShadowRadius(1, SHADOW_RADIUS);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
index 2d3ebb4..aadff76 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
@@ -27,7 +27,8 @@
class CreateDisplayTest : public DisplayTransactionTest {
public:
- void createDisplayWithRequestedRefreshRate(const std::string& name, uint64_t displayId,
+ void createDisplayWithRequestedRefreshRate(const std::string& name,
+ VirtualDisplayId::BaseId baseId,
float pacesetterDisplayRefreshRate,
float requestedRefreshRate,
float expectedAdjustedRefreshRate) {
@@ -49,12 +50,10 @@
EXPECT_EQ(display.requestedRefreshRate, Fps::fromValue(requestedRefreshRate));
EXPECT_EQ(name.c_str(), display.displayName);
- std::optional<VirtualDisplayId> vid =
- DisplayId::fromValue<VirtualDisplayId>(displayId | DisplayId::FLAG_VIRTUAL);
- ASSERT_TRUE(vid.has_value());
-
+ const VirtualDisplayId vid = GpuVirtualDisplayId(baseId);
sp<DisplayDevice> device =
- mFlinger.createVirtualDisplayDevice(displayToken, *vid, requestedRefreshRate);
+ mFlinger.createVirtualDisplayDevice(displayToken, vid, requestedRefreshRate);
+
EXPECT_TRUE(device->isVirtual());
device->adjustRefreshRate(Fps::fromValue(pacesetterDisplayRefreshRate));
// verifying desired value