Merge "Run libinput_tests on host"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index a60972b..a62bd01 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -126,6 +126,7 @@
     ],
     required: [
         "atrace",
+        "bugreport_procdump",
         "dmabuf_dump",
         "ip",
         "iptables",
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 60c2077..b076c15 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1624,7 +1624,8 @@
     RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
                             "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
 
-    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "BUGREPORT_PROCDUMP", {"bugreport_procdump"},
+                                         CommandOptions::AS_ROOT);
 
     RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpVisibleWindowViews);
 
@@ -1641,9 +1642,6 @@
     RunCommand("PROCESSES AND THREADS",
                {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
 
-    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
-                                         CommandOptions::AS_ROOT);
-
     if (ds.dump_pool_) {
         WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_hals));
     } else {
@@ -1673,8 +1671,6 @@
 
     RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
 
-    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
-
     for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
     for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
 
@@ -3922,15 +3918,6 @@
     return;
 }
 
-void do_showmap(int pid, const char *name) {
-    char title[255];
-    char arg[255];
-
-    snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name);
-    snprintf(arg, sizeof(arg), "%d", pid);
-    RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT);
-}
-
 int Dumpstate::DumpFile(const std::string& title, const std::string& path) {
     DurationReporter duration_reporter(title);
 
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index ee6b1ae..66f84cb 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -619,9 +619,6 @@
 /* Displays a processes times */
 void show_showtime(int pid, const char *name);
 
-/* Runs "showmap" for a process */
-void do_showmap(int pid, const char *name);
-
 /* Gets the dmesg output for the kernel */
 void do_dmesg();
 
diff --git a/cmds/installd/otapreopt.rc b/cmds/installd/otapreopt.rc
index 059ae75..0bad0c5 100644
--- a/cmds/installd/otapreopt.rc
+++ b/cmds/installd/otapreopt.rc
@@ -5,4 +5,4 @@
     # The dalvik-cache was not moved itself, so as to restrict the rights of otapreopt_slot.
     # But now the relabeling is annoying as there is no force option available here. So
     # explicitly list all the ISAs we know.
-    restorecon_recursive /data/dalvik-cache/arm /data/dalvik-cache/arm64 /data/dalvik-cache/mips /data/dalvik-cache/mips64 /data/dalvik-cache/x86 /data/dalvik-cache/x86_64
+    restorecon_recursive /data/dalvik-cache/arm /data/dalvik-cache/arm64 /data/dalvik-cache/riscv64 /data/dalvik-cache/x86 /data/dalvik-cache/x86_64
diff --git a/include/android/surface_control_jni.h b/include/android/surface_control_jni.h
index 67e3a9f..a0a1fdb 100644
--- a/include/android/surface_control_jni.h
+++ b/include/android/surface_control_jni.h
@@ -36,14 +36,15 @@
 /**
  * Return the ASurfaceControl wrapped by a Java SurfaceControl object.
  *
- * This method does not acquire any additional reference to the ASurfaceControl
- * that is returned. To keep the ASurfaceControl alive after the Java
- * SurfaceControl object is closed, explicitly or by the garbage collector, be
- * sure to use ASurfaceControl_acquire() to acquire an additional reference.
+ * The caller takes ownership of the returned ASurfaceControl returned and must
+ * release it * using ASurfaceControl_release.
+ *
+ * surfaceControlObj must be a non-null instance of android.view.SurfaceControl
+ * and isValid() must be true.
  *
  * Available since API level 34.
  */
-ASurfaceControl* _Nullable ASurfaceControl_fromSurfaceControl(JNIEnv* _Nonnull env,
+ASurfaceControl* _Nonnull ASurfaceControl_fromSurfaceControl(JNIEnv* _Nonnull env,
         jobject _Nonnull surfaceControlObj) __INTRODUCED_IN(__ANDROID_API_U__);
 
 /**
@@ -52,11 +53,13 @@
  * The returned ASurfaceTransaction is still owned by the Java Transaction object is only
  * valid while the Java Transaction object is alive. In particular, the returned transaction
  * must NOT be deleted with ASurfaceTransaction_delete.
- * May return nullptr on error.
+ *
+ * transactionObj must be a non-null instance of
+ * android.view.SurfaceControl.Transaction and close() must not already be called.
  *
  * Available since API level 34.
  */
-ASurfaceTransaction* _Nullable ASurfaceTransaction_fromTransaction(JNIEnv* _Nonnull env,
+ASurfaceTransaction* _Nonnull ASurfaceTransaction_fromTransaction(JNIEnv* _Nonnull env,
         jobject _Nonnull transactionObj) __INTRODUCED_IN(__ANDROID_API_U__);
 
 __END_DECLS
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 0026e82..f4a1523 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -280,6 +280,9 @@
 
     std::vector<InputDeviceLightInfo> getLights();
 
+    inline void setSupportsUsi(bool supportsUsi) { mSupportsUsi = supportsUsi; }
+    inline bool supportsUsi() const { return mSupportsUsi; }
+
 private:
     int32_t mId;
     int32_t mGeneration;
@@ -292,6 +295,8 @@
     uint32_t mSources;
     int32_t mKeyboardType;
     std::shared_ptr<KeyCharacterMap> mKeyCharacterMap;
+    // Whether this device supports the Universal Stylus Initiative (USI) protocol for styluses.
+    bool mSupportsUsi;
 
     bool mHasVibrator;
     bool mHasBattery;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 735f294..04d4a07 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -25,6 +25,7 @@
 #include <android/gui/ISurfaceComposerClient.h>
 #include <android/gui/IWindowInfosListener.h>
 #include <android/os/IInputConstants.h>
+#include <gui/TraceUtils.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/SortedVector.h>
@@ -910,9 +911,14 @@
     uncacheBuffer.token = BufferCache::getInstance().getToken();
     uncacheBuffer.id = cacheId;
 
-    sf->setTransactionState(FrameTimelineInfo{}, {}, {}, ISurfaceComposer::eOneWay,
-                            Transaction::getDefaultApplyToken(), {}, systemTime(), true,
-                            uncacheBuffer, false, {}, generateId());
+    status_t status =
+            sf->setTransactionState(FrameTimelineInfo{}, {}, {}, ISurfaceComposer::eOneWay,
+                                    Transaction::getDefaultApplyToken(), {}, systemTime(), true,
+                                    uncacheBuffer, false, {}, generateId());
+    if (status != NO_ERROR) {
+        ALOGE_AND_TRACE("SurfaceComposerClient::doUncacheBufferTransaction - %s",
+                        strerror(-status));
+    }
 }
 
 void SurfaceComposerClient::Transaction::cacheBuffers() {
diff --git a/libs/gui/include/gui/TraceUtils.h b/libs/gui/include/gui/TraceUtils.h
index 4c01683..441b833 100644
--- a/libs/gui/include/gui/TraceUtils.h
+++ b/libs/gui/include/gui/TraceUtils.h
@@ -30,6 +30,12 @@
 #define ATRACE_FORMAT_INSTANT(fmt, ...) \
     (CC_UNLIKELY(ATRACE_ENABLED()) && (TraceUtils::instantFormat(fmt, ##__VA_ARGS__), true))
 
+#define ALOGE_AND_TRACE(fmt, ...)                  \
+    do {                                           \
+        ALOGE(fmt, ##__VA_ARGS__);                 \
+        ATRACE_FORMAT_INSTANT(fmt, ##__VA_ARGS__); \
+    } while (false)
+
 namespace android {
 
 class TraceUtils {
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 3fe03c7..4751a7d 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -182,6 +182,7 @@
         mSources(other.mSources),
         mKeyboardType(other.mKeyboardType),
         mKeyCharacterMap(other.mKeyCharacterMap),
+        mSupportsUsi(other.mSupportsUsi),
         mHasVibrator(other.mHasVibrator),
         mHasBattery(other.mHasBattery),
         mHasButtonUnderPad(other.mHasButtonUnderPad),
@@ -210,6 +211,7 @@
     mHasBattery = false;
     mHasButtonUnderPad = false;
     mHasSensor = false;
+    mSupportsUsi = false;
     mMotionRanges.clear();
     mSensors.clear();
     mLights.clear();
diff --git a/libs/jpegrecoverymap/Android.bp b/libs/jpegrecoverymap/Android.bp
new file mode 100644
index 0000000..285f8d5
--- /dev/null
+++ b/libs/jpegrecoverymap/Android.bp
@@ -0,0 +1,34 @@
+// Copyright 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.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_static {
+    name: "libjpegrecoverymap",
+    vendor_available: true,
+
+    export_include_dirs: ["include"],
+    local_include_dirs: ["include"],
+
+    srcs: [
+        "recoverymap.cpp",
+    ],
+}
\ No newline at end of file
diff --git a/libs/jpegrecoverymap/OWNERS b/libs/jpegrecoverymap/OWNERS
new file mode 100644
index 0000000..6ace354
--- /dev/null
+++ b/libs/jpegrecoverymap/OWNERS
@@ -0,0 +1,3 @@
+arifdikici@google.com
+dichenzhang@google.com
+kyslov@google.com
\ No newline at end of file
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h
new file mode 100644
index 0000000..c5f8e9a
--- /dev/null
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 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.
+ */
+
+namespace android::recoverymap {
+
+class RecoveryMap {
+public:
+    /*
+     * This method is called in the decoding pipeline. It will decode the recovery map.
+     *
+     * input: compressed recovery map
+     * output: uncompressed recovery map
+     */
+    void* decodeRecoveryMap(void* compressed_recovery_map);
+
+    /*
+     * This method is called in the encoding pipeline. It will encode the recovery map.
+     *
+     * input: uncompressed recovery map
+     * output: compressed recovery map
+     */
+    void* encodeRecoveryMap(void* uncompressed_recovery_map);
+
+    /*
+     * This method is called in the encoding pipeline. It will take the uncompressed 8-bit and
+     * 10-bit yuv images as input, and calculate the uncompressed recovery map.
+     *
+     * input: uncompressed yuv_420 image, uncompressed p010 image
+     * output: uncompressed recovery map
+     */
+    void* generateRecoveryMap(void* uncompressed_yuv_420_image, void* uncompressed_p010_image);
+
+    /*
+     * This method is called in the decoding pipeline. It will take the uncompressed (decoded)
+     * 8-bit yuv image and the uncompressed(decoded) recovery map as input, and calculate the
+     * 10-bit recovered image (in p010 color format).
+     *
+     * input: uncompressed yuv_420 image, uncompressed recovery map
+     * output: uncompress p010 image
+     */
+    void* applyRecoveryMap(void* uncompressed_yuv_420_image, void* uncompressed_recovery_map);
+
+    /*
+     * This method is called in the decoding pipeline. It will read XMP metadata to find the start
+     * position of the compressed recovery map, and will extract the compressed recovery map.
+     *
+     * input: compressed JPEG-G image (8-bit JPEG + compressed recovery map)
+     * output: compressed recovery map
+     */
+    void* extractRecoveryMap(void* compressed_jpeg_g_image);
+
+    /*
+     * This method is called in the encoding pipeline. It will take the standard 8-bit JPEG image
+     * and the compressed recovery map as input, and update the XMP metadata with the end of JPEG
+     * marker, and append the compressed gian map after the JPEG.
+     *
+     * input: compressed 8-bit JPEG image (standard JPEG), compressed recovery map
+     * output: compressed JPEG-G image (8-bit JPEG + compressed recovery map)
+     */
+    void* appendRecoveryMap(void* compressed_jpeg_image, void* compressed_recovery_map);
+};
+
+} // namespace android::recoverymap
\ No newline at end of file
diff --git a/libs/jpegrecoverymap/recoverymap.cpp b/libs/jpegrecoverymap/recoverymap.cpp
new file mode 100644
index 0000000..3e95a31
--- /dev/null
+++ b/libs/jpegrecoverymap/recoverymap.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright 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.
+ */
+
+#include <jpegrecoverymap/recoverymap.h>
+
+namespace android::recoverymap {
+
+void* RecoveryMap::decodeRecoveryMap(void* compressed_recovery_map) {
+  if (compressed_recovery_map == nullptr) {
+    return nullptr;
+  }
+
+  // TBD
+  return nullptr;
+}
+
+void* RecoveryMap::encodeRecoveryMap(void* uncompressed_recovery_map) {
+  if (uncompressed_recovery_map == nullptr) {
+    return nullptr;
+  }
+
+  // TBD
+  return nullptr;
+}
+
+void* RecoveryMap::generateRecoveryMap(
+    void* uncompressed_yuv_420_image, void* uncompressed_p010_image) {
+  if (uncompressed_yuv_420_image == nullptr || uncompressed_p010_image == nullptr) {
+    return nullptr;
+  }
+
+  // TBD
+  return nullptr;
+}
+
+void* RecoveryMap::applyRecoveryMap(
+    void* uncompressed_yuv_420_image, void* uncompressed_recovery_map) {
+  if (uncompressed_yuv_420_image == nullptr || uncompressed_recovery_map == nullptr) {
+    return nullptr;
+  }
+
+  // TBD
+  return nullptr;
+}
+
+void* RecoveryMap::extractRecoveryMap(void* compressed_jpeg_g_image) {
+  if (compressed_jpeg_g_image == nullptr) {
+    return nullptr;
+  }
+
+  // TBD
+  return nullptr;
+}
+
+void* RecoveryMap::appendRecoveryMap(void* compressed_jpeg_image, void* compressed_recovery_map) {
+  if (compressed_jpeg_image == nullptr || compressed_recovery_map == nullptr) {
+    return nullptr;
+  }
+
+  // TBD
+  return nullptr;
+}
+
+} // namespace android::recoverymap
diff --git a/libs/jpegrecoverymap/tests/Android.bp b/libs/jpegrecoverymap/tests/Android.bp
new file mode 100644
index 0000000..79bf723
--- /dev/null
+++ b/libs/jpegrecoverymap/tests/Android.bp
@@ -0,0 +1,33 @@
+// Copyright 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.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_test {
+    name: "libjpegrecoverymap_test",
+    test_suites: ["device-tests"],
+    srcs: [
+        "recoverymap_test.cpp",
+    ],
+    static_libs: [
+        "libjpegrecoverymap",
+    ],
+}
\ No newline at end of file
diff --git a/libs/jpegrecoverymap/tests/recoverymap_test.cpp b/libs/jpegrecoverymap/tests/recoverymap_test.cpp
new file mode 100644
index 0000000..c436138
--- /dev/null
+++ b/libs/jpegrecoverymap/tests/recoverymap_test.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright 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.
+ */
+
+#include <jpegrecoverymap/recoverymap.h>
+
+namespace android {
+
+// Add new tests here.
+} // namespace android
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index da58efd..18a73ea 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -189,73 +189,74 @@
 void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
     InputMapper::populateDeviceInfo(info);
 
-    if (mDeviceMode != DeviceMode::DISABLED) {
-        info->addMotionRange(mOrientedRanges.x);
-        info->addMotionRange(mOrientedRanges.y);
-        info->addMotionRange(mOrientedRanges.pressure);
-
-        if (mDeviceMode == DeviceMode::UNSCALED && mSource == AINPUT_SOURCE_TOUCHPAD) {
-            // Populate RELATIVE_X and RELATIVE_Y motion ranges for touchpad capture mode.
-            //
-            // RELATIVE_X and RELATIVE_Y motion ranges should be the largest possible relative
-            // motion, i.e. the hardware dimensions, as the finger could move completely across the
-            // touchpad in one sample cycle.
-            const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
-            const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
-            info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -x.max, x.max, x.flat,
-                                 x.fuzz, x.resolution);
-            info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -y.max, y.max, y.flat,
-                                 y.fuzz, y.resolution);
-        }
-
-        if (mOrientedRanges.size) {
-            info->addMotionRange(*mOrientedRanges.size);
-        }
-
-        if (mOrientedRanges.touchMajor) {
-            info->addMotionRange(*mOrientedRanges.touchMajor);
-            info->addMotionRange(*mOrientedRanges.touchMinor);
-        }
-
-        if (mOrientedRanges.toolMajor) {
-            info->addMotionRange(*mOrientedRanges.toolMajor);
-            info->addMotionRange(*mOrientedRanges.toolMinor);
-        }
-
-        if (mOrientedRanges.orientation) {
-            info->addMotionRange(*mOrientedRanges.orientation);
-        }
-
-        if (mOrientedRanges.distance) {
-            info->addMotionRange(*mOrientedRanges.distance);
-        }
-
-        if (mOrientedRanges.tilt) {
-            info->addMotionRange(*mOrientedRanges.tilt);
-        }
-
-        if (mCursorScrollAccumulator.haveRelativeVWheel()) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
-                                 0.0f);
-        }
-        if (mCursorScrollAccumulator.haveRelativeHWheel()) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
-                                 0.0f);
-        }
-        if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
-            const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
-            const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
-            info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat,
-                                 x.fuzz, x.resolution);
-            info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat,
-                                 y.fuzz, y.resolution);
-            info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat,
-                                 x.fuzz, x.resolution);
-            info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat,
-                                 y.fuzz, y.resolution);
-        }
-        info->setButtonUnderPad(mParameters.hasButtonUnderPad);
+    if (mDeviceMode == DeviceMode::DISABLED) {
+        return;
     }
+
+    info->addMotionRange(mOrientedRanges.x);
+    info->addMotionRange(mOrientedRanges.y);
+    info->addMotionRange(mOrientedRanges.pressure);
+
+    if (mDeviceMode == DeviceMode::UNSCALED && mSource == AINPUT_SOURCE_TOUCHPAD) {
+        // Populate RELATIVE_X and RELATIVE_Y motion ranges for touchpad capture mode.
+        //
+        // RELATIVE_X and RELATIVE_Y motion ranges should be the largest possible relative
+        // motion, i.e. the hardware dimensions, as the finger could move completely across the
+        // touchpad in one sample cycle.
+        const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
+        const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
+        info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -x.max, x.max, x.flat, x.fuzz,
+                             x.resolution);
+        info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -y.max, y.max, y.flat, y.fuzz,
+                             y.resolution);
+    }
+
+    if (mOrientedRanges.size) {
+        info->addMotionRange(*mOrientedRanges.size);
+    }
+
+    if (mOrientedRanges.touchMajor) {
+        info->addMotionRange(*mOrientedRanges.touchMajor);
+        info->addMotionRange(*mOrientedRanges.touchMinor);
+    }
+
+    if (mOrientedRanges.toolMajor) {
+        info->addMotionRange(*mOrientedRanges.toolMajor);
+        info->addMotionRange(*mOrientedRanges.toolMinor);
+    }
+
+    if (mOrientedRanges.orientation) {
+        info->addMotionRange(*mOrientedRanges.orientation);
+    }
+
+    if (mOrientedRanges.distance) {
+        info->addMotionRange(*mOrientedRanges.distance);
+    }
+
+    if (mOrientedRanges.tilt) {
+        info->addMotionRange(*mOrientedRanges.tilt);
+    }
+
+    if (mCursorScrollAccumulator.haveRelativeVWheel()) {
+        info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+    }
+    if (mCursorScrollAccumulator.haveRelativeHWheel()) {
+        info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+    }
+    if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
+        const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
+        const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
+        info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat, x.fuzz,
+                             x.resolution);
+        info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat, y.fuzz,
+                             y.resolution);
+        info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat, x.fuzz,
+                             x.resolution);
+        info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, y.fuzz,
+                             y.resolution);
+    }
+    info->setButtonUnderPad(mParameters.hasButtonUnderPad);
+    info->setSupportsUsi(mParameters.supportsUsi);
 }
 
 void TouchInputMapper::dump(std::string& dump) {
@@ -395,13 +396,11 @@
     }
 
     if (changes && resetNeeded) {
-        // If the device needs to be reset, cancel any ongoing gestures and reset the state.
-        out += cancelTouch(when, when);
         out += reset(when);
 
         // Send reset, unless this is the first time the device has been configured,
         // in which case the reader will call reset itself after all mappers are ready.
-        out.push_back(NotifyDeviceResetArgs(getContext()->getNextId(), when, getDeviceId()));
+        out.emplace_back(NotifyDeviceResetArgs(getContext()->getNextId(), when, getDeviceId()));
     }
     return out;
 }
@@ -507,6 +506,10 @@
     // up in your pocket but you can enable it using the input device configuration.
     mParameters.wake = getDeviceContext().isExternal();
     getDeviceContext().getConfiguration().tryGetProperty("touch.wake", mParameters.wake);
+
+    mParameters.supportsUsi = false;
+    getDeviceContext().getConfiguration().tryGetProperty("touch.supportsUsi",
+                                                         mParameters.supportsUsi);
 }
 
 void TouchInputMapper::dumpParameters(std::string& dump) {
@@ -523,6 +526,7 @@
                          mParameters.uniqueDisplayId.c_str());
     dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
     dump += INDENT4 "Orientation: " + ftl::enum_string(mParameters.orientation) + "\n";
+    dump += StringPrintf(INDENT4 "SupportsUsi: %s\n", toString(mParameters.supportsUsi));
 }
 
 void TouchInputMapper::configureRawPointerAxes() {
@@ -1440,6 +1444,9 @@
 }
 
 std::list<NotifyArgs> TouchInputMapper::reset(nsecs_t when) {
+    std::list<NotifyArgs> out = cancelTouch(when, when);
+    updateTouchSpots();
+
     mCursorButtonAccumulator.reset(getDeviceContext());
     mCursorScrollAccumulator.reset(getDeviceContext());
     mTouchButtonAccumulator.reset(getDeviceContext());
@@ -1470,7 +1477,7 @@
         mPointerController->clearSpots();
     }
 
-    return InputMapper::reset(when);
+    return out += InputMapper::reset(when);
 }
 
 void TouchInputMapper::resetExternalStylus() {
@@ -1554,10 +1561,7 @@
 std::list<NotifyArgs> TouchInputMapper::processRawTouches(bool timeout) {
     std::list<NotifyArgs> out;
     if (mDeviceMode == DeviceMode::DISABLED) {
-        // Drop all input if the device is disabled.
-        out += cancelTouch(mCurrentRawState.when, mCurrentRawState.readTime);
-        mCurrentCookedState.clear();
-        updateTouchSpots();
+        // Do not process raw event while the device is disabled.
         return out;
     }
 
@@ -1976,8 +1980,8 @@
         int32_t metaState = getContext()->getGlobalMetaState();
         int32_t buttonState = mCurrentCookedState.buttonState;
         out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
-                                     AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
-                                     AMOTION_EVENT_EDGE_FLAG_NONE,
+                                     AMOTION_EVENT_ACTION_CANCEL, 0, AMOTION_EVENT_FLAG_CANCELED,
+                                     metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
                                      mCurrentCookedState.cookedPointerData.pointerProperties,
                                      mCurrentCookedState.cookedPointerData.pointerCoords,
                                      mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits,
@@ -2617,8 +2621,9 @@
     BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits);
     if (!dispatchedGestureIdBits.isEmpty()) {
         if (cancelPreviousGesture) {
+            const uint32_t cancelFlags = flags | AMOTION_EVENT_FLAG_CANCELED;
             out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
-                                         AMOTION_EVENT_ACTION_CANCEL, 0, flags, metaState,
+                                         AMOTION_EVENT_ACTION_CANCEL, 0, cancelFlags, metaState,
                                          buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
                                          mPointerGesture.lastGestureProperties,
                                          mPointerGesture.lastGestureCoords,
@@ -2754,8 +2759,8 @@
         int32_t metaState = getContext()->getGlobalMetaState();
         int32_t buttonState = mCurrentRawState.buttonState;
         out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
-                                     AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
-                                     AMOTION_EVENT_EDGE_FLAG_NONE,
+                                     AMOTION_EVENT_ACTION_CANCEL, 0, AMOTION_EVENT_FLAG_CANCELED,
+                                     metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
                                      mPointerGesture.lastGestureProperties,
                                      mPointerGesture.lastGestureCoords,
                                      mPointerGesture.lastGestureIdToIndex,
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 50f30c8..7b0327e 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -232,6 +232,9 @@
         GestureMode gestureMode;
 
         bool wake;
+
+        // Whether the device supports the Universal Stylus Initiative (USI) protocol for styluses.
+        bool supportsUsi;
     } mParameters;
 
     // Immutable calibration parameters in parsed form.
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index dded6a1..8ac8dfc 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -3112,6 +3112,15 @@
         return processArgList;
     }
 
+    void resetMapper(InputMapper& mapper, nsecs_t when) {
+        const auto resetArgs = mapper.reset(when);
+        for (const auto args : resetArgs) {
+            mFakeListener->notify(args);
+        }
+        // Loop the reader to flush the input listener queue.
+        mReader->loopOnce();
+    }
+
     static void assertMotionRange(const InputDeviceInfo& info,
             int32_t axis, uint32_t source, float min, float max, float flat, float fuzz) {
         const InputDeviceInfo::MotionRange* range = info.getMotionRange(axis, source);
@@ -6864,6 +6873,28 @@
             toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
 }
 
+TEST_F(SingleTouchInputMapperTest, Reset_CancelsOngoingGesture) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareButtons();
+    prepareAxes(POSITION | PRESSURE);
+    SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+
+    // Touch down.
+    processDown(mapper, 100, 200);
+    processPressure(mapper, 1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+            WithMotionAction(AMOTION_EVENT_ACTION_DOWN)));
+
+    // Reset the mapper. This should cancel the ongoing gesture.
+    resetMapper(mapper, ARBITRARY_TIME);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+            WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)));
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+}
+
 TEST_F(SingleTouchInputMapperTest, Reset_RecreatesTouchState) {
     addConfigurationProperty("touch.deviceType", "touchScreen");
     prepareDisplay(DISPLAY_ORIENTATION_0);
@@ -6878,8 +6909,9 @@
     mFakeEventHub->setScanCodeState(EVENTHUB_ID, BTN_TOUCH, 1);
 
     // Reset the mapper. When the mapper is reset, we expect it to attempt to recreate the touch
-    // state by reading the current axis values.
-    std::list<NotifyArgs> unused = mapper.reset(ARBITRARY_TIME);
+    // state by reading the current axis values. Since there was no ongoing gesture, calling reset
+    // does not generate any events.
+    resetMapper(mapper, ARBITRARY_TIME);
 
     // Send a sync to simulate an empty touch frame where nothing changes. The mapper should use
     // the recreated touch state to generate a down event.
@@ -9530,9 +9562,10 @@
             mFakeListener->assertNotifyMotionWasCalled(WithMotionAction(ACTION_POINTER_1_DOWN)));
 
     // Reset the mapper. When the mapper is reset, we expect the current multi-touch state to be
-    // preserved. Resetting should not generate any events.
-    std::list<NotifyArgs> unused = mapper.reset(ARBITRARY_TIME);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+    // preserved. Resetting should cancel the ongoing gesture.
+    resetMapper(mapper, ARBITRARY_TIME);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+            WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)));
 
     // Send a sync to simulate an empty touch frame where nothing changes. The mapper should use
     // the existing touch state to generate a down event.
@@ -9566,7 +9599,7 @@
 
     // Reset the mapper. When the mapper is reset, we expect it to restore the latest
     // raw state where no pointers are down.
-    std::list<NotifyArgs> unused = mapper.reset(ARBITRARY_TIME);
+    resetMapper(mapper, ARBITRARY_TIME);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
 
     // Send an empty sync frame. Since there are no pointers, no events are generated.
diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h
index 2580405..ff7455b 100644
--- a/services/inputflinger/tests/TestInputListenerMatchers.h
+++ b/services/inputflinger/tests/TestInputListenerMatchers.h
@@ -23,13 +23,19 @@
 namespace android {
 
 MATCHER_P(WithMotionAction, action, "InputEvent with specified action") {
-    if (action == AMOTION_EVENT_ACTION_CANCEL) {
-        *result_listener << "expected FLAG_CANCELED to be set with ACTION_CANCEL, but was not set";
-        return (arg.flags & AMOTION_EVENT_FLAG_CANCELED) != 0;
+    bool matches = action == arg.action;
+    if (!matches) {
+        *result_listener << "expected action " << MotionEvent::actionToString(action)
+                         << ", but got " << MotionEvent::actionToString(arg.action);
     }
-    *result_listener << "expected action " << MotionEvent::actionToString(action) << ", but got "
-                     << MotionEvent::actionToString(arg.action);
-    return action == arg.action;
+    if (action == AMOTION_EVENT_ACTION_CANCEL) {
+        if (!matches) {
+            *result_listener << "; ";
+        }
+        *result_listener << "expected FLAG_CANCELED to be set with ACTION_CANCEL, but was not set";
+        matches &= (arg.flags & AMOTION_EVENT_FLAG_CANCELED) != 0;
+    }
+    return matches;
 }
 
 MATCHER_P(WithSource, source, "InputEvent with specified source") {
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
index cf932a8..b01932e 100644
--- a/services/surfaceflinger/ClientCache.cpp
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -22,6 +22,7 @@
 #include <cinttypes>
 
 #include <android-base/stringprintf.h>
+#include <gui/TraceUtils.h>
 #include <renderengine/impl/ExternalTexture.h>
 
 #include "ClientCache.h"
@@ -36,12 +37,12 @@
                             ClientCacheBuffer** outClientCacheBuffer) {
     auto& [processToken, id] = cacheId;
     if (processToken == nullptr) {
-        ALOGE("failed to get buffer, invalid (nullptr) process token");
+        ALOGE_AND_TRACE("ClientCache::getBuffer - invalid (nullptr) process token");
         return false;
     }
     auto it = mBuffers.find(processToken);
     if (it == mBuffers.end()) {
-        ALOGE("failed to get buffer, invalid process token");
+        ALOGE_AND_TRACE("ClientCache::getBuffer - invalid process token");
         return false;
     }
 
@@ -49,7 +50,7 @@
 
     auto bufItr = processBuffers.find(id);
     if (bufItr == processBuffers.end()) {
-        ALOGV("failed to get buffer, invalid buffer id");
+        ALOGE_AND_TRACE("ClientCache::getBuffer - invalid buffer id");
         return false;
     }
 
@@ -61,12 +62,12 @@
 bool ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) {
     auto& [processToken, id] = cacheId;
     if (processToken == nullptr) {
-        ALOGE("failed to cache buffer: invalid process token");
+        ALOGE_AND_TRACE("ClientCache::add - invalid (nullptr) process token");
         return false;
     }
 
     if (!buffer) {
-        ALOGE("failed to cache buffer: invalid buffer");
+        ALOGE_AND_TRACE("ClientCache::add - invalid (nullptr) buffer");
         return false;
     }
 
@@ -79,7 +80,7 @@
     if (it == mBuffers.end()) {
         token = processToken.promote();
         if (!token) {
-            ALOGE("failed to cache buffer: invalid token");
+            ALOGE_AND_TRACE("ClientCache::add - invalid token");
             return false;
         }
 
@@ -87,7 +88,7 @@
         if (token->localBinder() == nullptr) {
             status_t err = token->linkToDeath(mDeathRecipient);
             if (err != NO_ERROR) {
-                ALOGE("failed to cache buffer: could not link to death");
+                ALOGE_AND_TRACE("ClientCache::add - could not link to death");
                 return false;
             }
         }
@@ -102,7 +103,7 @@
     auto& processBuffers = it->second.second;
 
     if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
-        ALOGE("failed to cache buffer: cache is full");
+        ALOGE_AND_TRACE("ClientCache::add - cache is full");
         return false;
     }
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 98ab4d6..12949d6 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -739,13 +739,17 @@
     std::unordered_map<Fps, AggregatedFpsScore, FpsHash, FpsApproxEqual> aggregatedScoresPerFps =
             getAggregatedScoresPerFps(refreshRateRankingsAndSignalsPerDisplay);
 
-    Fps chosenFps = std::max_element(aggregatedScoresPerFps.begin(), aggregatedScoresPerFps.end(),
-                                     [](const auto& max, const auto& current) {
-                                         return max.second.totalScore <= current.second.totalScore;
-                                     })
-                            ->first;
-
-    return getDisplayModeConfigsForTheChosenFps(chosenFps, refreshRateRankingsAndSignalsPerDisplay);
+    auto maxScoreIt = aggregatedScoresPerFps.cbegin();
+    // Selects the max Fps that is present on all the displays.
+    for (auto it = aggregatedScoresPerFps.cbegin(); it != aggregatedScoresPerFps.cend(); ++it) {
+        const auto [fps, aggregatedScore] = *it;
+        if (aggregatedScore.numDisplays == mDisplays.size() &&
+            aggregatedScore.totalScore >= maxScoreIt->second.totalScore) {
+            maxScoreIt = it;
+        }
+    }
+    return getDisplayModeConfigsForTheChosenFps(maxScoreIt->first,
+                                                refreshRateRankingsAndSignalsPerDisplay);
 }
 
 std::vector<DisplayModeConfig> Scheduler::getDisplayModeConfigsForTheChosenFps(
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 8d2130f..406d2bc 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -65,6 +65,7 @@
     static inline const DisplayModePtr kMode120_1 = createDisplayMode(DisplayModeId(1), 120_Hz);
     static inline const DisplayModePtr kMode60_2 = createDisplayMode(DisplayModeId(2), 60_Hz);
     static inline const DisplayModePtr kMode120_2 = createDisplayMode(DisplayModeId(3), 120_Hz);
+    static inline const DisplayModePtr kMode60_3 = createDisplayMode(DisplayModeId(4), 60_Hz);
 
     std::shared_ptr<RefreshRateConfigs> mConfigs =
             std::make_shared<RefreshRateConfigs>(makeModes(kMode60_1), kMode60_1->getId());
@@ -305,7 +306,7 @@
     mScheduler->registerDisplay(display1);
     mScheduler->registerDisplay(display2);
 
-    const std::vector<sp<DisplayDevice>>& expectedDisplays = {display1, display2};
+    std::vector<sp<DisplayDevice>> expectedDisplays = {display1, display2};
     std::vector<RefreshRateConfigs::LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
     GlobalSignals globalSignals = {.idle = true};
     std::vector<DisplayModeConfig> expectedConfigs = {DisplayModeConfig{globalSignals, kMode60_1},
@@ -350,6 +351,32 @@
                 << displayModeConfigs.at(i).displayModePtr->getFps().getIntValue();
         EXPECT_EQ(globalSignals, displayModeConfigs.at(i).signals);
     }
+
+    // Filters out the 120Hz as it's not present on the display3, even with touch active
+    // we select 60Hz here.
+    auto display3 = mFakeDisplayInjector.injectDefaultInternalDisplay(
+            [&](FakeDisplayDeviceInjector& injector) {
+                injector.setDisplayModes(makeModes(kMode60_3), kMode60_3->getId());
+            },
+            mFlinger, /* port */ 252u);
+    mScheduler->registerDisplay(display3);
+
+    expectedDisplays = {display1, display2, display3};
+    globalSignals = {.touch = true};
+    mScheduler->replaceTouchTimer(10);
+    expectedConfigs = std::vector<DisplayModeConfig>{DisplayModeConfig{globalSignals, kMode60_1},
+                                                     DisplayModeConfig{globalSignals, kMode60_2},
+                                                     DisplayModeConfig{globalSignals, kMode60_3}};
+    mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
+    displayModeConfigs = mScheduler->getBestDisplayModeConfigs();
+    ASSERT_EQ(expectedConfigs.size(), displayModeConfigs.size());
+    for (size_t i = 0; i < expectedConfigs.size(); ++i) {
+        EXPECT_EQ(expectedConfigs.at(i).displayModePtr, displayModeConfigs.at(i).displayModePtr)
+                << "Expected fps " << expectedConfigs.at(i).displayModePtr->getFps().getIntValue()
+                << " Actual fps "
+                << displayModeConfigs.at(i).displayModePtr->getFps().getIntValue();
+        EXPECT_EQ(globalSignals, displayModeConfigs.at(i).signals);
+    }
 }
 
 } // namespace android::scheduler