summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/servicemanager/ServiceManager.cpp3
-rw-r--r--data/etc/android.software.opengles.deqp.level-2023-03-01.xml21
-rw-r--r--data/etc/android.software.vulkan.deqp.level-2023-03-01.xml21
-rw-r--r--libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs49
-rw-r--r--libs/binder/rust/tests/parcel_fuzzer/read_utils.rs152
-rw-r--r--libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h6
-rw-r--r--libs/jpegrecoverymap/recoverymap.cpp79
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp16
-rw-r--r--services/inputflinger/dispatcher/TouchState.cpp5
-rw-r--r--services/inputflinger/dispatcher/TouchState.h4
-rw-r--r--services/inputflinger/reader/Android.bp1
-rw-r--r--services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp157
-rw-r--r--services/inputflinger/reader/mapper/MultiTouchInputMapper.h69
-rw-r--r--services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp176
-rw-r--r--services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h96
-rw-r--r--services/inputflinger/tests/InputReader_test.cpp92
-rw-r--r--services/inputflinger/tests/UinputDevice.cpp26
-rw-r--r--services/inputflinger/tests/UinputDevice.h39
-rw-r--r--services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h1
19 files changed, 639 insertions, 374 deletions
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 2684f048f8..2ae61b9603 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -612,7 +612,8 @@ void ServiceManager::binderDied(const wp<IBinder>& who) {
}
void ServiceManager::tryStartService(const std::string& name) {
- ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service",
+ ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service. (if it's not "
+ "configured to be a lazy service, it may be stuck starting or still starting).",
name.c_str());
std::thread([=] {
diff --git a/data/etc/android.software.opengles.deqp.level-2023-03-01.xml b/data/etc/android.software.opengles.deqp.level-2023-03-01.xml
new file mode 100644
index 0000000000..d0b594c73d
--- /dev/null
+++ b/data/etc/android.software.opengles.deqp.level-2023-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device passes OpenGL ES
+ dEQP tests associated with date 2023-03-01 (0x07E70301). -->
+<permissions>
+ <feature name="android.software.opengles.deqp.level" version="132580097" />
+</permissions>
diff --git a/data/etc/android.software.vulkan.deqp.level-2023-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2023-03-01.xml
new file mode 100644
index 0000000000..6ae248ac3c
--- /dev/null
+++ b/data/etc/android.software.vulkan.deqp.level-2023-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
+ tests associated with date 2023-03-01 (0x07E70301). -->
+<permissions>
+ <feature name="android.software.vulkan.deqp.level" version="132580097" />
+</permissions>
diff --git a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
index 21271d2484..c5c7719df2 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
+++ b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
@@ -22,7 +22,7 @@ extern crate libfuzzer_sys;
mod read_utils;
-use crate::read_utils::get_read_funcs;
+use crate::read_utils::READ_FUNCS;
use binder::binder_impl::{
Binder, BorrowedParcel, IBinderInternal, Parcel, Stability, TransactionCode,
};
@@ -34,18 +34,18 @@ use binder_random_parcel_rs::create_random_parcel;
use libfuzzer_sys::arbitrary::Arbitrary;
#[derive(Arbitrary, Debug)]
-enum ReadOperations {
+enum ReadOperation {
SetDataPosition { pos: i32 },
GetDataSize,
ReadParcelableHolder { is_vintf: bool },
- ReadBasicTypes { indexes: Vec<usize> },
+ ReadBasicTypes { instructions: Vec<usize> },
}
#[derive(Arbitrary, Debug)]
-enum Operations<'a> {
+enum Operation<'a> {
Transact { code: u32, flag: u32, data: &'a [u8] },
Append { start: i32, len: i32, data1: &'a [u8], data2: &'a [u8], append_all: bool },
- Read { indexes: Vec<ReadOperations>, data: &'a [u8] },
+ Read { read_operations: Vec<ReadOperation>, data: &'a [u8] },
}
/// Interface to fuzz transact with random parcel
@@ -102,13 +102,12 @@ fn do_append_fuzz(start: i32, len: i32, data1: &[u8], data2: &[u8], append_all:
};
}
-fn do_read_fuzz(read_operations: Vec<ReadOperations>, data: &[u8]) {
- let read_funcs = get_read_funcs();
+fn do_read_fuzz(read_operations: Vec<ReadOperation>, data: &[u8]) {
let parcel = create_random_parcel(data);
for operation in read_operations {
match operation {
- ReadOperations::SetDataPosition { pos } => {
+ ReadOperation::SetDataPosition { pos } => {
unsafe {
// Safety: Safe if pos is less than current size of the parcel.
// It relies on C++ code for bound checks
@@ -119,12 +118,12 @@ fn do_read_fuzz(read_operations: Vec<ReadOperations>, data: &[u8]) {
}
}
- ReadOperations::GetDataSize => {
+ ReadOperation::GetDataSize => {
let data_size = parcel.get_data_size();
println!("data size from parcel: {:?}", data_size);
}
- ReadOperations::ReadParcelableHolder { is_vintf } => {
+ ReadOperation::ReadParcelableHolder { is_vintf } => {
let stability = if is_vintf { Stability::Vintf } else { Stability::Local };
let mut holder: ParcelableHolder = ParcelableHolder::new(stability);
match holder.read_from_parcel(parcel.borrowed_ref()) {
@@ -135,30 +134,28 @@ fn do_read_fuzz(read_operations: Vec<ReadOperations>, data: &[u8]) {
}
}
- ReadOperations::ReadBasicTypes { indexes } => {
- for index in indexes.iter() {
- let read_index = index % read_funcs.len();
- read_funcs[read_index](parcel.borrowed_ref());
+ ReadOperation::ReadBasicTypes { instructions } => {
+ for instruction in instructions.iter() {
+ let read_index = instruction % READ_FUNCS.len();
+ READ_FUNCS[read_index](parcel.borrowed_ref());
}
}
}
}
}
-fuzz_target!(|operations: Vec<Operations>| {
- for operation in operations {
- match operation {
- Operations::Transact { code, flag, data } => {
- do_transact(code, data, flag);
- }
+fuzz_target!(|operation: Operation| {
+ match operation {
+ Operation::Transact { code, flag, data } => {
+ do_transact(code, data, flag);
+ }
- Operations::Append { start, len, data1, data2, append_all } => {
- do_append_fuzz(start, len, data1, data2, append_all);
- }
+ Operation::Append { start, len, data1, data2, append_all } => {
+ do_append_fuzz(start, len, data1, data2, append_all);
+ }
- Operations::Read { indexes, data } => {
- do_read_fuzz(indexes, data);
- }
+ Operation::Read { read_operations, data } => {
+ do_read_fuzz(read_operations, data);
}
}
});
diff --git a/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs
index 9b06013332..d2bfde1022 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs
+++ b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs
@@ -22,7 +22,7 @@ use binderReadParcelIface::aidl::SingleDataParcelable::SingleDataParcelable;
macro_rules! read_parcel_interface {
($data_type:ty) => {
- |parcel| {
+ |parcel: &BorrowedParcel<'_>| {
let _res = parcel.read::<$data_type>();
}
};
@@ -57,81 +57,77 @@ impl binder::Parcelable for SomeParcelable {
binder::impl_deserialize_for_parcelable!(SomeParcelable);
-pub fn get_read_funcs() -> Vec<Box<dyn Fn(&BorrowedParcel<'_>)>> {
- let read_funcs: Vec<Box<dyn Fn(&BorrowedParcel<'_>)>> = vec![
- //read basic types
- Box::new(read_parcel_interface!(bool)),
- Box::new(read_parcel_interface!(i8)),
- Box::new(read_parcel_interface!(i32)),
- Box::new(read_parcel_interface!(i64)),
- Box::new(read_parcel_interface!(f32)),
- Box::new(read_parcel_interface!(f64)),
- Box::new(read_parcel_interface!(u16)),
- Box::new(read_parcel_interface!(u32)),
- Box::new(read_parcel_interface!(u64)),
- Box::new(read_parcel_interface!(String)),
- //read vec of basic types
- Box::new(read_parcel_interface!(Vec<i8>)),
- Box::new(read_parcel_interface!(Vec<i32>)),
- Box::new(read_parcel_interface!(Vec<i64>)),
- Box::new(read_parcel_interface!(Vec<f32>)),
- Box::new(read_parcel_interface!(Vec<f64>)),
- Box::new(read_parcel_interface!(Vec<u16>)),
- Box::new(read_parcel_interface!(Vec<u32>)),
- Box::new(read_parcel_interface!(Vec<u64>)),
- Box::new(read_parcel_interface!(Vec<String>)),
- Box::new(read_parcel_interface!(Option<Vec<i8>>)),
- Box::new(read_parcel_interface!(Option<Vec<i32>>)),
- Box::new(read_parcel_interface!(Option<Vec<i64>>)),
- Box::new(read_parcel_interface!(Option<Vec<f32>>)),
- Box::new(read_parcel_interface!(Option<Vec<f64>>)),
- Box::new(read_parcel_interface!(Option<Vec<u16>>)),
- Box::new(read_parcel_interface!(Option<Vec<u32>>)),
- Box::new(read_parcel_interface!(Option<Vec<u64>>)),
- Box::new(read_parcel_interface!(Option<Vec<String>>)),
- Box::new(read_parcel_interface!(ParcelFileDescriptor)),
- Box::new(read_parcel_interface!(Vec<Option<ParcelFileDescriptor>>)),
- Box::new(read_parcel_interface!(Option<Vec<ParcelFileDescriptor>>)),
- Box::new(read_parcel_interface!(Option<Vec<Option<ParcelFileDescriptor>>>)),
- Box::new(read_parcel_interface!(SpIBinder)),
- Box::new(read_parcel_interface!(Vec<Option<SpIBinder>>)),
- Box::new(read_parcel_interface!(Option<Vec<SpIBinder>>)),
- Box::new(read_parcel_interface!(Option<Vec<Option<SpIBinder>>>)),
- Box::new(read_parcel_interface!(SomeParcelable)),
- Box::new(read_parcel_interface!(Vec<Option<SomeParcelable>>)),
- Box::new(read_parcel_interface!(Option<Vec<SomeParcelable>>)),
- Box::new(read_parcel_interface!(Option<Vec<Option<SomeParcelable>>>)),
- // Fuzz read_from_parcel for AIDL generated parcelables
- Box::new(|parcel| {
- let mut empty_parcelable: EmptyParcelable = EmptyParcelable::default();
- match empty_parcelable.read_from_parcel(parcel) {
- Ok(result) => result,
- Err(e) => {
- println!("EmptyParcelable: error occurred while reading from a parcel: {:?}", e)
- }
+pub const READ_FUNCS: &[fn(&BorrowedParcel<'_>)] = &[
+ //read basic types
+ read_parcel_interface!(bool),
+ read_parcel_interface!(i8),
+ read_parcel_interface!(i32),
+ read_parcel_interface!(i64),
+ read_parcel_interface!(f32),
+ read_parcel_interface!(f64),
+ read_parcel_interface!(u16),
+ read_parcel_interface!(u32),
+ read_parcel_interface!(u64),
+ read_parcel_interface!(String),
+ //read vec of basic types
+ read_parcel_interface!(Vec<i8>),
+ read_parcel_interface!(Vec<i32>),
+ read_parcel_interface!(Vec<i64>),
+ read_parcel_interface!(Vec<f32>),
+ read_parcel_interface!(Vec<f64>),
+ read_parcel_interface!(Vec<u16>),
+ read_parcel_interface!(Vec<u32>),
+ read_parcel_interface!(Vec<u64>),
+ read_parcel_interface!(Vec<String>),
+ read_parcel_interface!(Option<Vec<i8>>),
+ read_parcel_interface!(Option<Vec<i32>>),
+ read_parcel_interface!(Option<Vec<i64>>),
+ read_parcel_interface!(Option<Vec<f32>>),
+ read_parcel_interface!(Option<Vec<f64>>),
+ read_parcel_interface!(Option<Vec<u16>>),
+ read_parcel_interface!(Option<Vec<u32>>),
+ read_parcel_interface!(Option<Vec<u64>>),
+ read_parcel_interface!(Option<Vec<String>>),
+ read_parcel_interface!(ParcelFileDescriptor),
+ read_parcel_interface!(Vec<Option<ParcelFileDescriptor>>),
+ read_parcel_interface!(Option<Vec<ParcelFileDescriptor>>),
+ read_parcel_interface!(Option<Vec<Option<ParcelFileDescriptor>>>),
+ read_parcel_interface!(SpIBinder),
+ read_parcel_interface!(Vec<Option<SpIBinder>>),
+ read_parcel_interface!(Option<Vec<SpIBinder>>),
+ read_parcel_interface!(Option<Vec<Option<SpIBinder>>>),
+ read_parcel_interface!(SomeParcelable),
+ read_parcel_interface!(Vec<Option<SomeParcelable>>),
+ read_parcel_interface!(Option<Vec<SomeParcelable>>),
+ read_parcel_interface!(Option<Vec<Option<SomeParcelable>>>),
+ // Fuzz read_from_parcel for AIDL generated parcelables
+ |parcel| {
+ let mut empty_parcelable: EmptyParcelable = EmptyParcelable::default();
+ match empty_parcelable.read_from_parcel(parcel) {
+ Ok(result) => result,
+ Err(e) => {
+ println!("EmptyParcelable: error occurred while reading from a parcel: {:?}", e)
}
- }),
- Box::new(|parcel| {
- let mut single_parcelable: SingleDataParcelable = SingleDataParcelable::default();
- match single_parcelable.read_from_parcel(parcel) {
- Ok(result) => result,
- Err(e) => println!(
- "SingleDataParcelable: error occurred while reading from a parcel: {:?}",
- e
- ),
- }
- }),
- Box::new(|parcel| {
- let mut generic_parcelable: GenericDataParcelable = GenericDataParcelable::default();
- match generic_parcelable.read_from_parcel(parcel) {
- Ok(result) => result,
- Err(e) => println!(
- "GenericDataParcelable: error occurred while reading from a parcel: {:?}",
- e
- ),
- }
- }),
- ];
-
- read_funcs
-}
+ }
+ },
+ |parcel| {
+ let mut single_parcelable: SingleDataParcelable = SingleDataParcelable::default();
+ match single_parcelable.read_from_parcel(parcel) {
+ Ok(result) => result,
+ Err(e) => println!(
+ "SingleDataParcelable: error occurred while reading from a parcel: {:?}",
+ e
+ ),
+ }
+ },
+ |parcel| {
+ let mut generic_parcelable: GenericDataParcelable = GenericDataParcelable::default();
+ match generic_parcelable.read_from_parcel(parcel) {
+ Ok(result) => result,
+ Err(e) => println!(
+ "GenericDataParcelable: error occurred while reading from a parcel: {:?}",
+ e
+ ),
+ }
+ },
+];
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h
index 8e36250e60..b2ca481aa7 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h
@@ -176,11 +176,13 @@ private:
* @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format
* @param uncompressed_p010_image uncompressed HDR image in P010 color format
* @param dest recovery map; caller responsible for memory of data
+ * @param hdr_ratio HDR ratio will be updated in this method
* @return NO_ERROR if calculation succeeds, error code if error occurs.
*/
status_t generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image,
jr_uncompressed_ptr uncompressed_p010_image,
- jr_uncompressed_ptr dest);
+ jr_uncompressed_ptr dest,
+ float &hdr_ratio);
/*
* This method is called in the decoding pipeline. It will take the uncompressed (decoded)
@@ -213,11 +215,13 @@ private:
*
* @param compressed_jpeg_image compressed 8-bit JPEG image
* @param compress_recovery_map compressed recover map
+ * @param hdr_ratio HDR ratio
* @param dest compressed JPEGR image
* @return NO_ERROR if calculation succeeds, error code if error occurs.
*/
status_t appendRecoveryMap(jr_compressed_ptr compressed_jpeg_image,
jr_compressed_ptr compressed_recovery_map,
+ float hdr_ratio,
jr_compressed_ptr dest);
/*
diff --git a/libs/jpegrecoverymap/recoverymap.cpp b/libs/jpegrecoverymap/recoverymap.cpp
index d46025c441..bd16a68b0d 100644
--- a/libs/jpegrecoverymap/recoverymap.cpp
+++ b/libs/jpegrecoverymap/recoverymap.cpp
@@ -20,11 +20,11 @@
// TODO: handle PQ encode/decode (currently only HLG)
#include <jpegrecoverymap/recoverymap.h>
-
#include <jpegrecoverymap/jpegencoder.h>
#include <jpegrecoverymap/jpegdecoder.h>
#include <jpegrecoverymap/recoverymapmath.h>
+#include <image_io/jpeg/jpeg_marker.h>
#include <image_io/xml/xml_writer.h>
#include <memory>
@@ -60,6 +60,25 @@ string Name(const string &prefix, const string &suffix) {
return ss.str();
}
+/*
+ * Helper function used for writing data to destination.
+ *
+ * @param destination destination of the data to be written.
+ * @param source source of data being written.
+ * @param length length of the data to be written.
+ * @param position cursor in desitination where the data is to be written.
+ * @return status of succeed or error code.
+ */
+status_t Write(jr_compressed_ptr destination, const void* source, size_t length, int &position) {
+ if (position + length > destination->length) {
+ return ERROR_JPEGR_BUFFER_TOO_SMALL;
+ }
+
+ memcpy((uint8_t*)destination->data + sizeof(uint8_t) * position, source, length);
+ position += length;
+ return NO_ERROR;
+}
+
status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
jr_uncompressed_ptr uncompressed_yuv_420_image,
jr_compressed_ptr dest,
@@ -81,7 +100,9 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
}
jpegr_uncompressed_struct map;
- JPEGR_CHECK(generateRecoveryMap(uncompressed_yuv_420_image, uncompressed_p010_image, &map));
+ float hdr_ratio = 0.0f;
+ JPEGR_CHECK(generateRecoveryMap(
+ uncompressed_yuv_420_image, uncompressed_p010_image, &map, hdr_ratio));
std::unique_ptr<uint8_t[]> map_data;
map_data.reset(reinterpret_cast<uint8_t*>(map.data));
@@ -102,7 +123,7 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
jpeg.data = jpeg_encoder.getCompressedImagePtr();
jpeg.length = jpeg_encoder.getCompressedImageSize();
- JPEGR_CHECK(appendRecoveryMap(&jpeg, &compressed_map, dest));
+ JPEGR_CHECK(appendRecoveryMap(&jpeg, &compressed_map, hdr_ratio, dest));
return NO_ERROR;
}
@@ -124,7 +145,9 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
}
jpegr_uncompressed_struct map;
- JPEGR_CHECK(generateRecoveryMap(uncompressed_yuv_420_image, uncompressed_p010_image, &map));
+ float hdr_ratio = 0.0f;
+ JPEGR_CHECK(generateRecoveryMap(
+ uncompressed_yuv_420_image, uncompressed_p010_image, &map, hdr_ratio));
std::unique_ptr<uint8_t[]> map_data;
map_data.reset(reinterpret_cast<uint8_t*>(map.data));
@@ -134,7 +157,7 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
compressed_map.data = compressed_map_data.get();
JPEGR_CHECK(compressRecoveryMap(&map, &compressed_map));
- JPEGR_CHECK(appendRecoveryMap(compressed_jpeg_image, &compressed_map, dest));
+ JPEGR_CHECK(appendRecoveryMap(compressed_jpeg_image, &compressed_map, hdr_ratio, dest));
return NO_ERROR;
}
@@ -163,7 +186,9 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
}
jpegr_uncompressed_struct map;
- JPEGR_CHECK(generateRecoveryMap(&uncompressed_yuv_420_image, uncompressed_p010_image, &map));
+ float hdr_ratio = 0.0f;
+ JPEGR_CHECK(generateRecoveryMap(
+ &uncompressed_yuv_420_image, uncompressed_p010_image, &map, hdr_ratio));
std::unique_ptr<uint8_t[]> map_data;
map_data.reset(reinterpret_cast<uint8_t*>(map.data));
@@ -173,7 +198,7 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
compressed_map.data = compressed_map_data.get();
JPEGR_CHECK(compressRecoveryMap(&map, &compressed_map));
- JPEGR_CHECK(appendRecoveryMap(compressed_jpeg_image, &compressed_map, dest));
+ JPEGR_CHECK(appendRecoveryMap(compressed_jpeg_image, &compressed_map, hdr_ratio, dest));
return NO_ERROR;
}
@@ -252,7 +277,8 @@ status_t RecoveryMap::compressRecoveryMap(jr_uncompressed_ptr uncompressed_recov
status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image,
jr_uncompressed_ptr uncompressed_p010_image,
- jr_uncompressed_ptr dest) {
+ jr_uncompressed_ptr dest,
+ float &hdr_ratio) {
if (uncompressed_yuv_420_image == nullptr
|| uncompressed_p010_image == nullptr
|| dest == nullptr) {
@@ -287,7 +313,7 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4
}
float y_hdr_max_nits = hlgInvOetf(yp_hdr_max);
- float hdr_ratio = y_hdr_max_nits / kSdrWhiteNits;
+ hdr_ratio = y_hdr_max_nits / kSdrWhiteNits;
for (size_t y = 0; y < map_height; ++y) {
for (size_t x = 0; x < map_width; ++x) {
@@ -364,6 +390,7 @@ status_t RecoveryMap::extractRecoveryMap(jr_compressed_ptr compressed_jpegr_imag
status_t RecoveryMap::appendRecoveryMap(jr_compressed_ptr compressed_jpeg_image,
jr_compressed_ptr compressed_recovery_map,
+ float hdr_ratio,
jr_compressed_ptr dest) {
if (compressed_jpeg_image == nullptr
|| compressed_recovery_map == nullptr
@@ -371,7 +398,39 @@ status_t RecoveryMap::appendRecoveryMap(jr_compressed_ptr compressed_jpeg_image,
return ERROR_JPEGR_INVALID_NULL_PTR;
}
- // TBD
+ string xmp = generateXmp(compressed_recovery_map->length, hdr_ratio);
+ string nameSpace = "http://ns.adobe.com/xap/1.0/\0";
+
+ // 2 bytes: APP1 sign (ff e1)
+ // 29 bytes: length of name space "http://ns.adobe.com/xap/1.0/\0"
+ // x bytes: length of xmp packet
+ int length = 2 + nameSpace.size() + xmp.size();
+ uint8_t lengthH = ((length >> 8) & 0xff);
+ uint8_t lengthL = (length & 0xff);
+
+ int pos = 0;
+
+ // JPEG/R structure:
+ // SOI (ff d8)
+ // APP1 (ff e1)
+ // 2 bytes of length (2 + 29 + length of xmp packet)
+ // name space ("http://ns.adobe.com/xap/1.0/\0")
+ // xmp
+ // primary image (without the first two bytes, the SOI sign)
+ // secondary image (the recovery map)
+ JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos));
+ JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kSOI, 1, pos));
+ JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos));
+ JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP1, 1, pos));
+ JPEGR_CHECK(Write(dest, &lengthH, 1, pos));
+ JPEGR_CHECK(Write(dest, &lengthL, 1, pos));
+ JPEGR_CHECK(Write(dest, (void*)nameSpace.c_str(), nameSpace.size(), pos));
+ JPEGR_CHECK(Write(dest, (void*)xmp.c_str(), xmp.size(), pos));
+ JPEGR_CHECK(Write(dest,
+ (uint8_t*)compressed_jpeg_image->data + 2, compressed_jpeg_image->length - 2, pos));
+ JPEGR_CHECK(Write(dest, compressed_recovery_map->data, compressed_recovery_map->length, pos));
+ dest->length = pos;
+
return NO_ERROR;
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 9a6ebaaed2..a47f40ccbb 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2104,7 +2104,7 @@ std::vector<TouchedWindow> InputDispatcher::findTouchedWindowTargetsLocked(
const bool isFromMouse = isFromSource(entry.source, AINPUT_SOURCE_MOUSE);
if (newGesture) {
bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
- if (switchedDevice && tempTouchState.down && !down && !isHoverAction) {
+ if (switchedDevice && tempTouchState.isDown() && !down && !isHoverAction) {
ALOGI("Dropping event because a pointer for a different device is already down "
"in display %" PRId32,
displayId);
@@ -2113,7 +2113,6 @@ std::vector<TouchedWindow> InputDispatcher::findTouchedWindowTargetsLocked(
return touchedWindows; // wrong device
}
tempTouchState.reset();
- tempTouchState.down = down;
tempTouchState.deviceId = entry.deviceId;
tempTouchState.source = entry.source;
tempTouchState.displayId = displayId;
@@ -2234,7 +2233,7 @@ std::vector<TouchedWindow> InputDispatcher::findTouchedWindowTargetsLocked(
/* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
// If the pointer is not currently down, then ignore the event.
- if (!tempTouchState.down) {
+ if (!tempTouchState.isDown()) {
if (DEBUG_FOCUS) {
ALOGD("Dropping event because the pointer is not down or we previously "
"dropped the pointer down event in display %" PRId32,
@@ -2445,7 +2444,7 @@ Failed:
if (isHoverAction) {
// Started hovering, therefore no longer down.
- if (oldState && oldState->down) {
+ if (oldState && oldState->isDown()) {
if (DEBUG_FOCUS) {
ALOGD("Conflicting pointer actions: Hover received while pointer was "
"down.");
@@ -2465,7 +2464,7 @@ Failed:
tempTouchState.reset();
} else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
// First pointer went down.
- if (oldState && oldState->down) {
+ if (oldState && oldState->isDown()) {
if (DEBUG_FOCUS) {
ALOGD("Conflicting pointer actions: Down received while already down.");
}
@@ -5326,9 +5325,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
dump += StringPrintf(INDENT "TouchStatesByDisplay:\n");
for (const std::pair<int32_t, TouchState>& pair : mTouchStatesByDisplay) {
const TouchState& state = pair.second;
- dump += StringPrintf(INDENT2 "%d: down=%s, deviceId=%d, source=0x%08x\n",
- state.displayId, toString(state.down), state.deviceId,
- state.source);
+ dump += StringPrintf(INDENT2 "%d: deviceId=%d, source=0x%08x\n", state.displayId,
+ state.deviceId, state.source);
if (!state.windows.empty()) {
dump += INDENT3 "Windows:\n";
for (size_t i = 0; i < state.windows.size(); i++) {
@@ -5688,7 +5686,7 @@ status_t InputDispatcher::pilferPointersLocked(const sp<IBinder>& token) {
}
auto [statePtr, windowPtr] = findTouchStateAndWindowLocked(token);
- if (statePtr == nullptr || windowPtr == nullptr || !statePtr->down) {
+ if (statePtr == nullptr || windowPtr == nullptr || windowPtr->pointerIds.isEmpty()) {
ALOGW("Attempted to pilfer points from a channel without any on-going pointer streams."
" Ignoring.");
return BAD_VALUE;
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index a3f45cfce3..f5b7cb88d9 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -138,4 +138,9 @@ sp<WindowInfoHandle> TouchState::getWallpaperWindow() const {
return nullptr;
}
+bool TouchState::isDown() const {
+ return std::any_of(windows.begin(), windows.end(),
+ [](const TouchedWindow& window) { return !window.pointerIds.isEmpty(); });
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index f6e9fb69f8..ceeeb1eb3d 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -28,8 +28,6 @@ class WindowInfoHandle;
namespace inputdispatcher {
struct TouchState {
- bool down = false;
-
// id of the device that is currently down, others are rejected
int32_t deviceId = -1;
// source of the device that is current down, others are rejected
@@ -59,6 +57,8 @@ struct TouchState {
sp<android::gui::WindowInfoHandle> getFirstForegroundWindowHandle() const;
bool isSlippery() const;
sp<android::gui::WindowInfoHandle> getWallpaperWindow() const;
+ // Whether any of the windows are currently being touched
+ bool isDown() const;
};
} // namespace inputdispatcher
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index a53fcd763d..24168a12a6 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -55,6 +55,7 @@ filegroup {
"mapper/accumulator/CursorButtonAccumulator.cpp",
"mapper/accumulator/CursorScrollAccumulator.cpp",
"mapper/accumulator/HidUsageAccumulator.cpp",
+ "mapper/accumulator/MultiTouchMotionAccumulator.cpp",
"mapper/accumulator/SingleTouchMotionAccumulator.cpp",
"mapper/accumulator/TouchButtonAccumulator.cpp",
],
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index acba4f6513..8e757a5bf7 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -28,163 +28,6 @@ namespace android {
// Maximum number of slots supported when using the slot-based Multitouch Protocol B.
static constexpr size_t MAX_SLOTS = 32;
-// --- MultiTouchMotionAccumulator ---
-
-MultiTouchMotionAccumulator::MultiTouchMotionAccumulator()
- : mCurrentSlot(-1),
- mUsingSlotsProtocol(false),
- mHaveStylus(false) {}
-
-void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount,
- bool usingSlotsProtocol) {
- mUsingSlotsProtocol = usingSlotsProtocol;
- mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE);
- mSlots = std::vector<Slot>(slotCount);
-
- mCurrentSlot = -1;
- if (mUsingSlotsProtocol) {
- // Query the driver for the current slot index and use it as the initial slot
- // before we start reading events from the device. It is possible that the
- // current slot index will not be the same as it was when the first event was
- // written into the evdev buffer, which means the input mapper could start
- // out of sync with the initial state of the events in the evdev buffer.
- // In the extremely unlikely case that this happens, the data from
- // two slots will be confused until the next ABS_MT_SLOT event is received.
- // This can cause the touch point to "jump", but at least there will be
- // no stuck touches.
- int32_t initialSlot;
- if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot);
- status == OK) {
- mCurrentSlot = initialSlot;
- } else {
- ALOGD("Could not retrieve current multi-touch slot index. status=%d", status);
- }
- }
-}
-
-void MultiTouchMotionAccumulator::resetSlots() {
- for (Slot& slot : mSlots) {
- slot.clear();
- }
- mCurrentSlot = -1;
-}
-
-void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
- if (rawEvent->type == EV_ABS) {
- bool newSlot = false;
- if (mUsingSlotsProtocol) {
- if (rawEvent->code == ABS_MT_SLOT) {
- mCurrentSlot = rawEvent->value;
- newSlot = true;
- }
- } else if (mCurrentSlot < 0) {
- mCurrentSlot = 0;
- }
-
- if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) {
- if (DEBUG_POINTERS) {
- if (newSlot) {
- ALOGW("MultiTouch device emitted invalid slot index %d but it "
- "should be between 0 and %zd; ignoring this slot.",
- mCurrentSlot, mSlots.size() - 1);
- }
- }
- } else {
- Slot& slot = mSlots[mCurrentSlot];
- // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of
- // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while
- // updating the slot.
- if (!mUsingSlotsProtocol) {
- slot.mInUse = true;
- }
-
- switch (rawEvent->code) {
- case ABS_MT_POSITION_X:
- slot.mAbsMTPositionX = rawEvent->value;
- warnIfNotInUse(*rawEvent, slot);
- break;
- case ABS_MT_POSITION_Y:
- slot.mAbsMTPositionY = rawEvent->value;
- warnIfNotInUse(*rawEvent, slot);
- break;
- case ABS_MT_TOUCH_MAJOR:
- slot.mAbsMTTouchMajor = rawEvent->value;
- break;
- case ABS_MT_TOUCH_MINOR:
- slot.mAbsMTTouchMinor = rawEvent->value;
- slot.mHaveAbsMTTouchMinor = true;
- break;
- case ABS_MT_WIDTH_MAJOR:
- slot.mAbsMTWidthMajor = rawEvent->value;
- break;
- case ABS_MT_WIDTH_MINOR:
- slot.mAbsMTWidthMinor = rawEvent->value;
- slot.mHaveAbsMTWidthMinor = true;
- break;
- case ABS_MT_ORIENTATION:
- slot.mAbsMTOrientation = rawEvent->value;
- break;
- case ABS_MT_TRACKING_ID:
- if (mUsingSlotsProtocol && rawEvent->value < 0) {
- // The slot is no longer in use but it retains its previous contents,
- // which may be reused for subsequent touches.
- slot.mInUse = false;
- } else {
- slot.mInUse = true;
- slot.mAbsMTTrackingId = rawEvent->value;
- }
- break;
- case ABS_MT_PRESSURE:
- slot.mAbsMTPressure = rawEvent->value;
- break;
- case ABS_MT_DISTANCE:
- slot.mAbsMTDistance = rawEvent->value;
- break;
- case ABS_MT_TOOL_TYPE:
- slot.mAbsMTToolType = rawEvent->value;
- slot.mHaveAbsMTToolType = true;
- break;
- }
- }
- } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
- // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
- mCurrentSlot += 1;
- }
-}
-
-void MultiTouchMotionAccumulator::finishSync() {
- if (!mUsingSlotsProtocol) {
- resetSlots();
- }
-}
-
-bool MultiTouchMotionAccumulator::hasStylus() const {
- return mHaveStylus;
-}
-
-void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Slot& slot) {
- if (!slot.mInUse) {
- ALOGW("Received unexpected event (0x%0x, 0x%0x) for slot %i with tracking id %i",
- event.code, event.value, mCurrentSlot, slot.mAbsMTTrackingId);
- }
-}
-
-// --- MultiTouchMotionAccumulator::Slot ---
-
-int32_t MultiTouchMotionAccumulator::Slot::getToolType() const {
- if (mHaveAbsMTToolType) {
- switch (mAbsMTToolType) {
- case MT_TOOL_FINGER:
- return AMOTION_EVENT_TOOL_TYPE_FINGER;
- case MT_TOOL_PEN:
- return AMOTION_EVENT_TOOL_TYPE_STYLUS;
- case MT_TOOL_PALM:
- return AMOTION_EVENT_TOOL_TYPE_PALM;
- }
- }
- return AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
-}
-
// --- MultiTouchInputMapper ---
MultiTouchInputMapper::MultiTouchInputMapper(InputDeviceContext& deviceContext)
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index 047e62de62..ddf9e80a6c 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -17,77 +17,10 @@
#pragma once
#include "TouchInputMapper.h"
+#include "accumulator/MultiTouchMotionAccumulator.h"
namespace android {
-/* Keeps track of the state of multi-touch protocol. */
-class MultiTouchMotionAccumulator {
-public:
- class Slot {
- public:
- inline bool isInUse() const { return mInUse; }
- inline int32_t getX() const { return mAbsMTPositionX; }
- inline int32_t getY() const { return mAbsMTPositionY; }
- inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; }
- inline int32_t getTouchMinor() const {
- return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor;
- }
- inline int32_t getToolMajor() const { return mAbsMTWidthMajor; }
- inline int32_t getToolMinor() const {
- return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor;
- }
- inline int32_t getOrientation() const { return mAbsMTOrientation; }
- inline int32_t getTrackingId() const { return mAbsMTTrackingId; }
- inline int32_t getPressure() const { return mAbsMTPressure; }
- inline int32_t getDistance() const { return mAbsMTDistance; }
- inline int32_t getToolType() const;
-
- private:
- friend class MultiTouchMotionAccumulator;
-
- bool mInUse = false;
- bool mHaveAbsMTTouchMinor = false;
- bool mHaveAbsMTWidthMinor = false;
- bool mHaveAbsMTToolType = false;
-
- int32_t mAbsMTPositionX = 0;
- int32_t mAbsMTPositionY = 0;
- int32_t mAbsMTTouchMajor = 0;
- int32_t mAbsMTTouchMinor = 0;
- int32_t mAbsMTWidthMajor = 0;
- int32_t mAbsMTWidthMinor = 0;
- int32_t mAbsMTOrientation = 0;
- int32_t mAbsMTTrackingId = -1;
- int32_t mAbsMTPressure = 0;
- int32_t mAbsMTDistance = 0;
- int32_t mAbsMTToolType = 0;
-
- void clear() { *this = Slot(); }
- };
-
- MultiTouchMotionAccumulator();
-
- void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol);
- void process(const RawEvent* rawEvent);
- void finishSync();
- bool hasStylus() const;
-
- inline size_t getSlotCount() const { return mSlots.size(); }
- inline const Slot& getSlot(size_t index) const {
- LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index);
- return mSlots[index];
- }
-
-private:
- int32_t mCurrentSlot;
- std::vector<Slot> mSlots;
- bool mUsingSlotsProtocol;
- bool mHaveStylus;
-
- void resetSlots();
- void warnIfNotInUse(const RawEvent& event, const Slot& slot);
-};
-
class MultiTouchInputMapper : public TouchInputMapper {
public:
explicit MultiTouchInputMapper(InputDeviceContext& deviceContext);
diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
new file mode 100644
index 0000000000..b0cef676fb
--- /dev/null
+++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// clang-format off
+#include "../Macros.h"
+// clang-format on
+#include "MultiTouchMotionAccumulator.h"
+
+namespace android {
+
+// --- MultiTouchMotionAccumulator ---
+
+MultiTouchMotionAccumulator::MultiTouchMotionAccumulator()
+ : mCurrentSlot(-1), mUsingSlotsProtocol(false), mHaveStylus(false) {}
+
+void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount,
+ bool usingSlotsProtocol) {
+ mUsingSlotsProtocol = usingSlotsProtocol;
+ mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE);
+ mSlots = std::vector<Slot>(slotCount);
+
+ mCurrentSlot = -1;
+ if (mUsingSlotsProtocol) {
+ // Query the driver for the current slot index and use it as the initial slot before we
+ // start reading events from the device. It is possible that the current slot index will
+ // not be the same as it was when the first event was written into the evdev buffer, which
+ // means the input mapper could start out of sync with the initial state of the events in
+ // the evdev buffer. In the extremely unlikely case that this happens, the data from two
+ // slots will be confused until the next ABS_MT_SLOT event is received. This can cause the
+ // touch point to "jump", but at least there will be no stuck touches.
+ int32_t initialSlot;
+ if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot);
+ status == OK) {
+ mCurrentSlot = initialSlot;
+ } else {
+ ALOGD("Could not retrieve current multi-touch slot index. status=%d", status);
+ }
+ }
+}
+
+void MultiTouchMotionAccumulator::resetSlots() {
+ for (Slot& slot : mSlots) {
+ slot.clear();
+ }
+ mCurrentSlot = -1;
+}
+
+void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
+ if (rawEvent->type == EV_ABS) {
+ bool newSlot = false;
+ if (mUsingSlotsProtocol) {
+ if (rawEvent->code == ABS_MT_SLOT) {
+ mCurrentSlot = rawEvent->value;
+ newSlot = true;
+ }
+ } else if (mCurrentSlot < 0) {
+ mCurrentSlot = 0;
+ }
+
+ if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) {
+ if (newSlot) {
+ ALOGW_IF(DEBUG_POINTERS,
+ "MultiTouch device emitted invalid slot index %d but it "
+ "should be between 0 and %zd; ignoring this slot.",
+ mCurrentSlot, mSlots.size() - 1);
+ }
+ } else {
+ Slot& slot = mSlots[mCurrentSlot];
+ // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of
+ // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while
+ // updating the slot.
+ if (!mUsingSlotsProtocol) {
+ slot.mInUse = true;
+ }
+
+ switch (rawEvent->code) {
+ case ABS_MT_POSITION_X:
+ slot.mAbsMtPositionX = rawEvent->value;
+ warnIfNotInUse(*rawEvent, slot);
+ break;
+ case ABS_MT_POSITION_Y:
+ slot.mAbsMtPositionY = rawEvent->value;
+ warnIfNotInUse(*rawEvent, slot);
+ break;
+ case ABS_MT_TOUCH_MAJOR:
+ slot.mAbsMtTouchMajor = rawEvent->value;
+ break;
+ case ABS_MT_TOUCH_MINOR:
+ slot.mAbsMtTouchMinor = rawEvent->value;
+ slot.mHaveAbsMtTouchMinor = true;
+ break;
+ case ABS_MT_WIDTH_MAJOR:
+ slot.mAbsMtWidthMajor = rawEvent->value;
+ break;
+ case ABS_MT_WIDTH_MINOR:
+ slot.mAbsMtWidthMinor = rawEvent->value;
+ slot.mHaveAbsMtWidthMinor = true;
+ break;
+ case ABS_MT_ORIENTATION:
+ slot.mAbsMtOrientation = rawEvent->value;
+ break;
+ case ABS_MT_TRACKING_ID:
+ if (mUsingSlotsProtocol && rawEvent->value < 0) {
+ // The slot is no longer in use but it retains its previous contents,
+ // which may be reused for subsequent touches.
+ slot.mInUse = false;
+ } else {
+ slot.mInUse = true;
+ slot.mAbsMtTrackingId = rawEvent->value;
+ }
+ break;
+ case ABS_MT_PRESSURE:
+ slot.mAbsMtPressure = rawEvent->value;
+ break;
+ case ABS_MT_DISTANCE:
+ slot.mAbsMtDistance = rawEvent->value;
+ break;
+ case ABS_MT_TOOL_TYPE:
+ slot.mAbsMtToolType = rawEvent->value;
+ slot.mHaveAbsMtToolType = true;
+ break;
+ }
+ }
+ } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
+ // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
+ mCurrentSlot += 1;
+ }
+}
+
+void MultiTouchMotionAccumulator::finishSync() {
+ if (!mUsingSlotsProtocol) {
+ resetSlots();
+ }
+}
+
+bool MultiTouchMotionAccumulator::hasStylus() const {
+ return mHaveStylus;
+}
+
+void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Slot& slot) {
+ if (!slot.mInUse) {
+ ALOGW("Received unexpected event (0x%0x, 0x%0x) for slot %i with tracking id %i",
+ event.code, event.value, mCurrentSlot, slot.mAbsMtTrackingId);
+ }
+}
+
+// --- MultiTouchMotionAccumulator::Slot ---
+
+int32_t MultiTouchMotionAccumulator::Slot::getToolType() const {
+ if (mHaveAbsMtToolType) {
+ switch (mAbsMtToolType) {
+ case MT_TOOL_FINGER:
+ return AMOTION_EVENT_TOOL_TYPE_FINGER;
+ case MT_TOOL_PEN:
+ return AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ case MT_TOOL_PALM:
+ return AMOTION_EVENT_TOOL_TYPE_PALM;
+ }
+ }
+ return AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
+}
+
+} // namespace android
diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h
new file mode 100644
index 0000000000..625a00fdd4
--- /dev/null
+++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <linux/input-event-codes.h>
+#include <stdint.h>
+#include <vector>
+
+#include "EventHub.h"
+#include "InputDevice.h"
+
+namespace android {
+
+/* Keeps track of the state of multi-touch protocol. */
+class MultiTouchMotionAccumulator {
+public:
+ class Slot {
+ public:
+ inline bool isInUse() const { return mInUse; }
+ inline int32_t getX() const { return mAbsMtPositionX; }
+ inline int32_t getY() const { return mAbsMtPositionY; }
+ inline int32_t getTouchMajor() const { return mAbsMtTouchMajor; }
+ inline int32_t getTouchMinor() const {
+ return mHaveAbsMtTouchMinor ? mAbsMtTouchMinor : mAbsMtTouchMajor;
+ }
+ inline int32_t getToolMajor() const { return mAbsMtWidthMajor; }
+ inline int32_t getToolMinor() const {
+ return mHaveAbsMtWidthMinor ? mAbsMtWidthMinor : mAbsMtWidthMajor;
+ }
+ inline int32_t getOrientation() const { return mAbsMtOrientation; }
+ inline int32_t getTrackingId() const { return mAbsMtTrackingId; }
+ inline int32_t getPressure() const { return mAbsMtPressure; }
+ inline int32_t getDistance() const { return mAbsMtDistance; }
+ int32_t getToolType() const;
+
+ private:
+ friend class MultiTouchMotionAccumulator;
+
+ bool mInUse = false;
+ bool mHaveAbsMtTouchMinor = false;
+ bool mHaveAbsMtWidthMinor = false;
+ bool mHaveAbsMtToolType = false;
+
+ int32_t mAbsMtPositionX = 0;
+ int32_t mAbsMtPositionY = 0;
+ int32_t mAbsMtTouchMajor = 0;
+ int32_t mAbsMtTouchMinor = 0;
+ int32_t mAbsMtWidthMajor = 0;
+ int32_t mAbsMtWidthMinor = 0;
+ int32_t mAbsMtOrientation = 0;
+ int32_t mAbsMtTrackingId = -1;
+ int32_t mAbsMtPressure = 0;
+ int32_t mAbsMtDistance = 0;
+ int32_t mAbsMtToolType = 0;
+
+ void clear() { *this = Slot(); }
+ };
+
+ MultiTouchMotionAccumulator();
+
+ void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol);
+ void process(const RawEvent* rawEvent);
+ void finishSync();
+ bool hasStylus() const;
+
+ inline size_t getSlotCount() const { return mSlots.size(); }
+ inline const Slot& getSlot(size_t index) const {
+ LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index);
+ return mSlots[index];
+ }
+
+private:
+ int32_t mCurrentSlot;
+ std::vector<Slot> mSlots;
+ bool mUsingSlotsProtocol;
+ bool mHaveStylus;
+
+ void resetSlots();
+ void warnIfNotInUse(const RawEvent& event, const Slot& slot);
+};
+
+} // namespace android
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index ecc42ba5c2..e4e22df5de 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -2373,7 +2373,7 @@ TEST_F(InputReaderIntegrationTest, TestInvalidDevice) {
// An invalid input device that is only used for this test.
class InvalidUinputDevice : public UinputDevice {
public:
- InvalidUinputDevice() : UinputDevice("Invalid Device") {}
+ InvalidUinputDevice() : UinputDevice("Invalid Device", 99 /*productId*/) {}
private:
void configureDevice(int fd, uinput_user_dev* device) override {}
@@ -2825,6 +2825,96 @@ TEST_F(TouchIntegrationTest, StylusButtonsGenerateKeyEvents) {
WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY))));
}
+TEST_F(TouchIntegrationTest, StylusButtonsSurroundingTouchGesture) {
+ const Point centerPoint = mDevice->getCenterPoint();
+
+ // Press the stylus button.
+ mDevice->sendKey(BTN_STYLUS, 1);
+ mDevice->sendSync();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(
+ AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithSource(AINPUT_SOURCE_KEYBOARD),
+ WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY))));
+
+ // Start and finish a stylus gesture.
+ mDevice->sendSlot(FIRST_SLOT);
+ mDevice->sendTrackingId(FIRST_TRACKING_ID);
+ mDevice->sendToolType(MT_TOOL_PEN);
+ mDevice->sendDown(centerPoint);
+ mDevice->sendSync();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS),
+ WithButtonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY))));
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS),
+ WithButtonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY))));
+
+ mDevice->sendTrackingId(INVALID_TRACKING_ID);
+ mDevice->sendSync();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0))));
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0))));
+
+ // Release the stylus button.
+ mDevice->sendKey(BTN_STYLUS, 0);
+ mDevice->sendSync();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(
+ AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP), WithSource(AINPUT_SOURCE_KEYBOARD),
+ WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY))));
+}
+
+TEST_F(TouchIntegrationTest, StylusButtonsWithinTouchGesture) {
+ const Point centerPoint = mDevice->getCenterPoint();
+
+ // Start a stylus gesture.
+ mDevice->sendSlot(FIRST_SLOT);
+ mDevice->sendTrackingId(FIRST_TRACKING_ID);
+ mDevice->sendToolType(MT_TOOL_PEN);
+ mDevice->sendDown(centerPoint);
+ mDevice->sendSync();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0))));
+
+ // Press and release a stylus button. Each change in button state also generates a MOVE event.
+ mDevice->sendKey(BTN_STYLUS, 1);
+ mDevice->sendSync();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(
+ AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithSource(AINPUT_SOURCE_KEYBOARD),
+ WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY))));
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS),
+ WithButtonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY))));
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS),
+ WithButtonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY))));
+
+ mDevice->sendKey(BTN_STYLUS, 0);
+ mDevice->sendSync();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(
+ AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP), WithSource(AINPUT_SOURCE_KEYBOARD),
+ WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY))));
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0))));
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0))));
+
+ // Finish the stylus gesture.
+ mDevice->sendTrackingId(INVALID_TRACKING_ID);
+ mDevice->sendSync();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
+ WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0))));
+}
+
// --- InputDeviceTest ---
class InputDeviceTest : public testing::Test {
protected:
diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp
index c4830dc815..bc695b8bd8 100644
--- a/services/inputflinger/tests/UinputDevice.cpp
+++ b/services/inputflinger/tests/UinputDevice.cpp
@@ -24,7 +24,8 @@ namespace android {
// --- UinputDevice ---
-UinputDevice::UinputDevice(const char* name) : mName(name) {}
+UinputDevice::UinputDevice(const char* name, int16_t productId)
+ : mName(name), mProductId(productId) {}
UinputDevice::~UinputDevice() {
if (ioctl(mDeviceFd, UI_DEV_DESTROY)) {
@@ -43,7 +44,7 @@ void UinputDevice::init() {
strlcpy(device.name, mName, UINPUT_MAX_NAME_SIZE);
device.id.bustype = BUS_USB;
device.id.vendor = 0x01;
- device.id.product = 0x01;
+ device.id.product = mProductId;
device.id.version = 1;
ASSERT_NO_FATAL_FAILURE(configureDevice(mDeviceFd, &device));
@@ -76,8 +77,8 @@ void UinputDevice::injectEvent(uint16_t type, uint16_t code, int32_t value) {
// --- UinputKeyboard ---
-UinputKeyboard::UinputKeyboard(const char* name, std::initializer_list<int> keys)
- : UinputDevice(name), mKeys(keys.begin(), keys.end()) {}
+UinputKeyboard::UinputKeyboard(const char* name, int16_t productId, std::initializer_list<int> keys)
+ : UinputDevice(name, productId), mKeys(keys.begin(), keys.end()) {}
void UinputKeyboard::configureDevice(int fd, uinput_user_dev* device) {
// enable key press/release event
@@ -121,23 +122,26 @@ void UinputKeyboard::pressAndReleaseKey(int key) {
// --- UinputHomeKey ---
-UinputHomeKey::UinputHomeKey() : UinputKeyboard("Test Uinput Home Key", {KEY_HOME}) {}
+UinputHomeKey::UinputHomeKey() : UinputKeyboard(DEVICE_NAME, PRODUCT_ID, {KEY_HOME}) {}
void UinputHomeKey::pressAndReleaseHomeKey() {
pressAndReleaseKey(KEY_HOME);
}
-// --- UinputSteamController
+// --- UinputSteamController ---
+
UinputSteamController::UinputSteamController()
- : UinputKeyboard("Test Uinput Steam Controller", {BTN_GEAR_DOWN, BTN_GEAR_UP}) {}
+ : UinputKeyboard(DEVICE_NAME, PRODUCT_ID, {BTN_GEAR_DOWN, BTN_GEAR_UP}) {}
+
+// --- UinputExternalStylus ---
-// --- UinputExternalStylus
UinputExternalStylus::UinputExternalStylus()
- : UinputKeyboard("Test Uinput External Stylus", {BTN_STYLUS, BTN_STYLUS2, BTN_STYLUS3}) {}
+ : UinputKeyboard(DEVICE_NAME, PRODUCT_ID, {BTN_STYLUS, BTN_STYLUS2, BTN_STYLUS3}) {}
// --- UinputTouchScreen ---
-UinputTouchScreen::UinputTouchScreen(const Rect* size)
- : UinputDevice(UinputTouchScreen::DEVICE_NAME), mSize(*size) {}
+
+UinputTouchScreen::UinputTouchScreen(const Rect& size)
+ : UinputDevice(DEVICE_NAME, PRODUCT_ID), mSize(size) {}
void UinputTouchScreen::configureDevice(int fd, uinput_user_dev* device) {
// Setup the touch screen device
diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h
index 53dcfd0a68..d661bd36d3 100644
--- a/services/inputflinger/tests/UinputDevice.h
+++ b/services/inputflinger/tests/UinputDevice.h
@@ -32,7 +32,7 @@ namespace android {
template <class D, class... Ts>
std::unique_ptr<D> createUinputDevice(Ts... args) {
// Using `new` to access non-public constructors.
- std::unique_ptr<D> dev(new D(&args...));
+ std::unique_ptr<D> dev(new D(args...));
EXPECT_NO_FATAL_FAILURE(dev->init());
return dev;
}
@@ -51,8 +51,9 @@ public:
protected:
const char* mName;
+ const int16_t mProductId;
- UinputDevice(const char* name);
+ explicit UinputDevice(const char* name, int16_t productId);
// Signals which types of events this device supports before it is created.
// This must be overridden by subclasses.
@@ -71,7 +72,8 @@ private:
class UinputKeyboard : public UinputDevice {
public:
- static constexpr const char* KEYBOARD_NAME = "Test Keyboard Device";
+ static constexpr const char* KEYBOARD_NAME = "Test Uinput Keyboard Device";
+ static constexpr int16_t PRODUCT_ID = 42;
// Injects key press and sync.
void pressKey(int key);
@@ -84,7 +86,8 @@ public:
friend std::unique_ptr<D> createUinputDevice(Ts... args);
protected:
- UinputKeyboard(const char* name, std::initializer_list<int> keys = {});
+ explicit UinputKeyboard(const char* name, int16_t productId = PRODUCT_ID,
+ std::initializer_list<int> keys = {});
private:
void configureDevice(int fd, uinput_user_dev* device) override;
@@ -97,6 +100,9 @@ private:
// A keyboard device that has a single HOME key.
class UinputHomeKey : public UinputKeyboard {
public:
+ static constexpr const char* DEVICE_NAME = "Test Uinput Home Key";
+ static constexpr int16_t PRODUCT_ID = 43;
+
// Injects 4 events: key press, sync, key release, and sync.
void pressAndReleaseHomeKey();
@@ -104,34 +110,47 @@ public:
friend std::unique_ptr<D> createUinputDevice(Ts... args);
private:
- UinputHomeKey();
+ explicit UinputHomeKey();
};
+// --- UinputSteamController ---
+
// A joystick device that sends a BTN_GEAR_DOWN / BTN_WHEEL key.
class UinputSteamController : public UinputKeyboard {
public:
+ static constexpr const char* DEVICE_NAME = "Test Uinput Steam Controller";
+ static constexpr int16_t PRODUCT_ID = 44;
+
template <class D, class... Ts>
friend std::unique_ptr<D> createUinputDevice(Ts... args);
private:
- UinputSteamController();
+ explicit UinputSteamController();
};
+// --- UinputExternalStylus ---
+
// A stylus that reports button presses.
class UinputExternalStylus : public UinputKeyboard {
public:
+ static constexpr const char* DEVICE_NAME = "Test Uinput External Stylus";
+ static constexpr int16_t PRODUCT_ID = 45;
+
template <class D, class... Ts>
friend std::unique_ptr<D> createUinputDevice(Ts... args);
private:
- UinputExternalStylus();
+ explicit UinputExternalStylus();
};
// --- UinputTouchScreen ---
-// A touch screen device with specific size.
+
+// A multi-touch touchscreen device with specific size that also supports styluses.
class UinputTouchScreen : public UinputDevice {
public:
- static constexpr const char* DEVICE_NAME = "Test Touch Screen";
+ static constexpr const char* DEVICE_NAME = "Test Uinput Touch Screen";
+ static constexpr int16_t PRODUCT_ID = 46;
+
static const int32_t RAW_TOUCH_MIN = 0;
static const int32_t RAW_TOUCH_MAX = 31;
static const int32_t RAW_ID_MIN = 0;
@@ -157,7 +176,7 @@ public:
const Point getCenterPoint();
protected:
- UinputTouchScreen(const Rect* size);
+ explicit UinputTouchScreen(const Rect& size);
private:
void configureDevice(int fd, uinput_user_dev* device) override;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h
index 5f749dfbcc..f4ded216cb 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h
@@ -42,6 +42,7 @@ public:
MOCK_METHOD(Status, updateTargetWorkDuration, (int64_t), (override));
MOCK_METHOD(Status, reportActualWorkDuration, (const ::std::vector<WorkDuration>&), (override));
MOCK_METHOD(Status, sendHint, (SessionHint), (override));
+ MOCK_METHOD(Status, setThreads, (const ::std::vector<int32_t>&), (override));
};
} // namespace android::Hwc2::mock