Merge "Save Layer instead of Handle to LayerCreatedState"
diff --git a/include/input/Input.h b/include/input/Input.h
index 5015e68..54c7114 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -803,6 +803,9 @@
 
     static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy);
 
+    static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&,
+                                               const PointerCoords&);
+
 protected:
     int32_t mAction;
     int32_t mActionButton;
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 137411b..53c9b78 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -688,7 +688,8 @@
 
     status_t status = OK;
     if (init) {
-        mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
+        status =
+                mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
     }
 
     {
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 50de22b..dba0a43 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -60,20 +60,21 @@
     RpcState();
     ~RpcState();
 
-    status_t readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
-                                    const sp<RpcSession>& session, uint32_t* version);
-    status_t sendConnectionInit(const sp<RpcSession::RpcConnection>& connection,
-                                const sp<RpcSession>& session);
-    status_t readConnectionInit(const sp<RpcSession::RpcConnection>& connection,
-                                const sp<RpcSession>& session);
+    [[nodiscard]] status_t readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
+                                                  const sp<RpcSession>& session, uint32_t* version);
+    [[nodiscard]] status_t sendConnectionInit(const sp<RpcSession::RpcConnection>& connection,
+                                              const sp<RpcSession>& session);
+    [[nodiscard]] status_t readConnectionInit(const sp<RpcSession::RpcConnection>& connection,
+                                              const sp<RpcSession>& session);
 
     // TODO(b/182940634): combine some special transactions into one "getServerInfo" call?
     sp<IBinder> getRootObject(const sp<RpcSession::RpcConnection>& connection,
                               const sp<RpcSession>& session);
-    status_t getMaxThreads(const sp<RpcSession::RpcConnection>& connection,
-                           const sp<RpcSession>& session, size_t* maxThreadsOut);
-    status_t getSessionId(const sp<RpcSession::RpcConnection>& connection,
-                          const sp<RpcSession>& session, std::vector<uint8_t>* sessionIdOut);
+    [[nodiscard]] status_t getMaxThreads(const sp<RpcSession::RpcConnection>& connection,
+                                         const sp<RpcSession>& session, size_t* maxThreadsOut);
+    [[nodiscard]] status_t getSessionId(const sp<RpcSession::RpcConnection>& connection,
+                                        const sp<RpcSession>& session,
+                                        std::vector<uint8_t>* sessionIdOut);
 
     [[nodiscard]] status_t transact(const sp<RpcSession::RpcConnection>& connection,
                                     const sp<IBinder>& address, uint32_t code, const Parcel& data,
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index a426713..aaa812b 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -179,7 +179,7 @@
 
     static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
                                     const sockaddr_storage addr, socklen_t addrLen);
-    status_t setupSocketServer(const RpcSocketAddress& address);
+    [[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address);
 
     const std::unique_ptr<RpcTransportCtx> mCtx;
     size_t mMaxThreads = 1;
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index bd1063d..1bc8464 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -136,7 +136,7 @@
      * Query the other side of the session for the maximum number of threads
      * it supports (maximum number of concurrent non-nested synchronous transactions)
      */
-    status_t getRemoteMaxThreads(size_t* maxThreads);
+    [[nodiscard]] status_t getRemoteMaxThreads(size_t* maxThreads);
 
     /**
      * See RpcTransportCtx::getCertificate
@@ -216,7 +216,7 @@
         bool allowNested = false;
     };
 
-    status_t readId();
+    [[nodiscard]] status_t readId();
 
     // A thread joining a server must always call these functions in order, and
     // cleanup is only programmed once into join. These are in separate
@@ -258,7 +258,7 @@
             std::unique_ptr<RpcTransport> rpcTransport);
     [[nodiscard]] bool removeIncomingConnection(const sp<RpcConnection>& connection);
 
-    status_t initShutdownTrigger();
+    [[nodiscard]] status_t initShutdownTrigger();
 
     enum class ConnectionUse {
         CLIENT,
@@ -269,8 +269,8 @@
     // Object representing exclusive access to a connection.
     class ExclusiveConnection {
     public:
-        static status_t find(const sp<RpcSession>& session, ConnectionUse use,
-                             ExclusiveConnection* connection);
+        [[nodiscard]] static status_t find(const sp<RpcSession>& session, ConnectionUse use,
+                                           ExclusiveConnection* connection);
 
         ~ExclusiveConnection();
         const sp<RpcConnection>& get() { return mConnection; }
diff --git a/libs/binder/include_tls/binder/RpcAuth.h b/libs/binder/include_tls/binder/RpcAuth.h
index 4c2f296..ab64828 100644
--- a/libs/binder/include_tls/binder/RpcAuth.h
+++ b/libs/binder/include_tls/binder/RpcAuth.h
@@ -40,7 +40,7 @@
     // - SSL_CTX_use_certificate
     // - SSL_CTX_set*_chain
     // - SSL_CTX_add0_chain_cert
-    virtual status_t configure(SSL_CTX* ctx) = 0;
+    [[nodiscard]] virtual status_t configure(SSL_CTX* ctx) = 0;
 };
 
 } // namespace android
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index 3e75d1b..bccfd2d 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -16,13 +16,12 @@
 
 use crate::binder::Stability;
 use crate::error::{Result, StatusCode};
-use crate::parcel::{Parcel, Parcelable};
+use crate::parcel::{OwnedParcel, Parcel, Parcelable};
 use crate::{impl_deserialize_for_parcelable, impl_serialize_for_parcelable};
 
-use downcast_rs::{impl_downcast, Downcast};
+use downcast_rs::{impl_downcast, DowncastSync};
 use std::any::Any;
-use std::cell::RefCell;
-use std::rc::Rc;
+use std::sync::{Arc, Mutex};
 
 /// Metadata that `ParcelableHolder` needs for all parcelables.
 ///
@@ -40,18 +39,18 @@
     }
 }
 
-trait AnyParcelable: Downcast + Parcelable + std::fmt::Debug {}
-impl_downcast!(AnyParcelable);
-impl<T> AnyParcelable for T where T: Downcast + Parcelable + std::fmt::Debug {}
+trait AnyParcelable: DowncastSync + Parcelable + std::fmt::Debug {}
+impl_downcast!(sync AnyParcelable);
+impl<T> AnyParcelable for T where T: DowncastSync + Parcelable + std::fmt::Debug {}
 
 #[derive(Debug, Clone)]
 enum ParcelableHolderData {
     Empty,
     Parcelable {
-        parcelable: Rc<dyn AnyParcelable>,
+        parcelable: Arc<dyn AnyParcelable>,
         name: String,
     },
-    Parcel(Parcel),
+    Parcel(OwnedParcel),
 }
 
 impl Default for ParcelableHolderData {
@@ -67,15 +66,15 @@
 /// `ParcelableHolder` is currently not thread-safe (neither
 /// `Send` nor `Sync`), mainly because it internally contains
 /// a `Parcel` which in turn is not thread-safe.
-#[derive(Debug, Default, Clone)]
+#[derive(Debug, Default)]
 pub struct ParcelableHolder {
-    // This is a `RefCell` because of `get_parcelable`
+    // This is a `Mutex` because of `get_parcelable`
     // which takes `&self` for consistency with C++.
     // We could make `get_parcelable` take a `&mut self`
-    // and get rid of the `RefCell` here for a performance
+    // and get rid of the `Mutex` here for a performance
     // improvement, but then callers would require a mutable
     // `ParcelableHolder` even for that getter method.
-    data: RefCell<ParcelableHolderData>,
+    data: Mutex<ParcelableHolderData>,
     stability: Stability,
 }
 
@@ -83,7 +82,7 @@
     /// Construct a new `ParcelableHolder` with the given stability.
     pub fn new(stability: Stability) -> Self {
         Self {
-            data: RefCell::new(ParcelableHolderData::Empty),
+            data: Mutex::new(ParcelableHolderData::Empty),
             stability,
         }
     }
@@ -93,20 +92,20 @@
     /// Note that this method does not reset the stability,
     /// only the contents.
     pub fn reset(&mut self) {
-        *self.data.get_mut() = ParcelableHolderData::Empty;
+        *self.data.get_mut().unwrap() = ParcelableHolderData::Empty;
         // We could also clear stability here, but C++ doesn't
     }
 
     /// Set the parcelable contained in this `ParcelableHolder`.
-    pub fn set_parcelable<T>(&mut self, p: Rc<T>) -> Result<()>
+    pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<()>
     where
-        T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug,
+        T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
     {
         if self.stability > p.get_stability() {
             return Err(StatusCode::BAD_VALUE);
         }
 
-        *self.data.get_mut() = ParcelableHolderData::Parcelable {
+        *self.data.get_mut().unwrap() = ParcelableHolderData::Parcelable {
             parcelable: p,
             name: T::get_descriptor().into(),
         };
@@ -127,12 +126,12 @@
     /// * `Ok(None)` if the holder is empty or the descriptor does not match
     /// * `Ok(Some(_))` if the object holds a parcelable of type `T`
     ///   with the correct descriptor
-    pub fn get_parcelable<T>(&self) -> Result<Option<Rc<T>>>
+    pub fn get_parcelable<T>(&self) -> Result<Option<Arc<T>>>
     where
-        T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug,
+        T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug + Send + Sync,
     {
         let parcelable_desc = T::get_descriptor();
-        let mut data = self.data.borrow_mut();
+        let mut data = self.data.lock().unwrap();
         match *data {
             ParcelableHolderData::Empty => Ok(None),
             ParcelableHolderData::Parcelable {
@@ -143,12 +142,13 @@
                     return Err(StatusCode::BAD_VALUE);
                 }
 
-                match Rc::clone(parcelable).downcast_rc::<T>() {
+                match Arc::clone(parcelable).downcast_arc::<T>() {
                     Err(_) => Err(StatusCode::BAD_VALUE),
                     Ok(x) => Ok(Some(x)),
                 }
             }
-            ParcelableHolderData::Parcel(ref parcel) => {
+            ParcelableHolderData::Parcel(ref mut parcel) => {
+                let parcel = parcel.borrowed();
                 unsafe {
                     // Safety: 0 should always be a valid position.
                     parcel.set_data_position(0)?;
@@ -160,10 +160,10 @@
                 }
 
                 let mut parcelable = T::default();
-                parcelable.read_from_parcel(parcel)?;
+                parcelable.read_from_parcel(&parcel)?;
 
-                let parcelable = Rc::new(parcelable);
-                let result = Rc::clone(&parcelable);
+                let parcelable = Arc::new(parcelable);
+                let result = Arc::clone(&parcelable);
                 *data = ParcelableHolderData::Parcelable { parcelable, name };
 
                 Ok(Some(result))
@@ -184,7 +184,8 @@
     fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()> {
         parcel.write(&self.stability)?;
 
-        match *self.data.borrow() {
+        let mut data = self.data.lock().unwrap();
+        match *data {
             ParcelableHolderData::Empty => parcel.write(&0i32),
             ParcelableHolderData::Parcelable {
                 ref parcelable,
@@ -212,9 +213,10 @@
 
                 Ok(())
             }
-            ParcelableHolderData::Parcel(ref p) => {
+            ParcelableHolderData::Parcel(ref mut p) => {
+                let p = p.borrowed();
                 parcel.write(&p.get_data_size())?;
-                parcel.append_all_from(p)
+                parcel.append_all_from(&p)
             }
         }
     }
@@ -229,7 +231,7 @@
             return Err(StatusCode::BAD_VALUE);
         }
         if data_size == 0 {
-            *self.data.get_mut() = ParcelableHolderData::Empty;
+            *self.data.get_mut().unwrap() = ParcelableHolderData::Empty;
             return Ok(());
         }
 
@@ -240,9 +242,11 @@
             .checked_add(data_size)
             .ok_or(StatusCode::BAD_VALUE)?;
 
-        let mut new_parcel = Parcel::new();
-        new_parcel.append_from(parcel, data_start, data_size)?;
-        *self.data.get_mut() = ParcelableHolderData::Parcel(new_parcel);
+        let mut new_parcel = OwnedParcel::new();
+        new_parcel
+            .borrowed()
+            .append_from(parcel, data_start, data_size)?;
+        *self.data.get_mut().unwrap() = ParcelableHolderData::Parcel(new_parcel);
 
         unsafe {
             // Safety: `append_from` checks if `data_size` overflows
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 0cbb880..7bbe3d7 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -663,13 +663,15 @@
                                         break;
                                     case AF_INET:
                                         CHECK_EQ(len, sizeof(sockaddr_in));
-                                        service->port = reinterpret_cast<const sockaddr_in*>(addr)
-                                                                ->sin_port;
+                                        service->port =
+                                                ntohs(reinterpret_cast<const sockaddr_in*>(addr)
+                                                              ->sin_port);
                                         break;
                                     case AF_INET6:
                                         CHECK_EQ(len, sizeof(sockaddr_in));
-                                        service->port = reinterpret_cast<const sockaddr_in6*>(addr)
-                                                                ->sin6_port;
+                                        service->port =
+                                                ntohs(reinterpret_cast<const sockaddr_in6*>(addr)
+                                                              ->sin6_port);
                                         break;
                                     default:
                                         LOG_ALWAYS_FATAL("Unrecognized address family %d",
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 8c359c7..19a29c1 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -208,7 +208,6 @@
     ],
 
     shared_libs: [
-        "android.frameworks.bufferhub@1.0",
         "libbinder",
         "libbufferhub",
         "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
@@ -234,7 +233,6 @@
                 "BufferHubProducer.cpp",
             ],
             exclude_shared_libs: [
-                "android.frameworks.bufferhub@1.0",
                 "libbufferhub",
                 "libbufferhubqueue",
                 "libpdx_default_transport",
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 390ff96..d018800 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -56,13 +56,8 @@
     transformedPoint.y -= origin.y;
 
     // Derive the transformed vector's clockwise angle from vertical.
-    float result = atan2f(transformedPoint.x, -transformedPoint.y);
-    if (result < -M_PI_2) {
-        result += M_PI;
-    } else if (result > M_PI_2) {
-        result -= M_PI;
-    }
-    return result;
+    // The return value of atan2f is in range [-pi, pi] which conforms to the orientation API.
+    return atan2f(transformedPoint.x, -transformedPoint.y);
 }
 
 vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) {
@@ -498,44 +493,14 @@
 
 float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
                                              size_t historicalIndex) const {
-    const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
-
-    if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
-        const vec2 xy = calculateTransformedXY(mSource, mRawTransform, coords->getXYValue());
-        static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
-        return xy[axis];
-    }
-
-    if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
-        const vec2 relativeXy =
-                transformWithoutTranslation(mRawTransform,
-                                            {coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
-                                             coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)});
-        return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
-    }
-
-    return coords->getAxisValue(axis);
+    const PointerCoords& coords = *getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
+    return calculateTransformedAxisValue(axis, mSource, mRawTransform, coords);
 }
 
 float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
                                           size_t historicalIndex) const {
-    const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
-
-    if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
-        const vec2 xy = calculateTransformedXY(mSource, mTransform, coords->getXYValue());
-        static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
-        return xy[axis];
-    }
-
-    if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
-        const vec2 relativeXy =
-                transformWithoutTranslation(mTransform,
-                                            {coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
-                                             coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)});
-        return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
-    }
-
-    return coords->getAxisValue(axis);
+    const PointerCoords& coords = *getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
+    return calculateTransformedAxisValue(axis, mSource, mTransform, coords);
 }
 
 ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
@@ -574,15 +539,6 @@
     ui::Transform newTransform;
     newTransform.set(matrix);
     mTransform = newTransform * mTransform;
-
-    // We need to update the AXIS_ORIENTATION value here to maintain the old behavior where the
-    // orientation angle is not affected by the initial transformation set in the MotionEvent.
-    std::for_each(mSamplePointerCoords.begin(), mSamplePointerCoords.end(),
-                  [&newTransform](PointerCoords& c) {
-                      float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
-                      c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
-                                     transformAngle(newTransform, orientation));
-                  });
 }
 
 void MotionEvent::applyTransform(const std::array<float, 9>& matrix) {
@@ -814,6 +770,30 @@
                                               : transform.transform(xy);
 }
 
+float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source,
+                                                 const ui::Transform& transform,
+                                                 const PointerCoords& coords) {
+    if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
+        const vec2 xy = calculateTransformedXY(source, transform, coords.getXYValue());
+        static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
+        return xy[axis];
+    }
+
+    if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
+        const vec2 relativeXy =
+                transformWithoutTranslation(transform,
+                                            {coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
+                                             coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)});
+        return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
+    }
+
+    if (axis == AMOTION_EVENT_AXIS_ORIENTATION) {
+        return transformAngle(transform, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
+    }
+
+    return coords.getAxisValue(axis);
+}
+
 // --- FocusEvent ---
 
 void FocusEvent::initialize(int32_t id, bool hasFocus, bool inTouchMode) {
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index a44f0b7..a6465ee 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -18,10 +18,10 @@
 //#define LOG_NDEBUG 0
 
 // Log debug messages about velocity tracking.
-#define DEBUG_VELOCITY 0
+static constexpr bool DEBUG_VELOCITY = false;
 
 // Log debug messages about the progress of the algorithm itself.
-#define DEBUG_STRATEGY 0
+static constexpr bool DEBUG_STRATEGY = false;
 
 #include <array>
 #include <inttypes.h>
@@ -30,7 +30,6 @@
 #include <optional>
 
 #include <android-base/stringprintf.h>
-#include <cutils/properties.h>
 #include <input/VelocityTracker.h>
 #include <utils/BitSet.h>
 #include <utils/Timers.h>
@@ -64,7 +63,6 @@
     return sqrtf(r);
 }
 
-#if DEBUG_STRATEGY || DEBUG_VELOCITY
 static std::string vectorToString(const float* a, uint32_t m) {
     std::string str;
     str += "[";
@@ -77,9 +75,11 @@
     str += " ]";
     return str;
 }
-#endif
 
-#if DEBUG_STRATEGY
+static std::string vectorToString(const std::vector<float>& v) {
+    return vectorToString(v.data(), v.size());
+}
+
 static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
     std::string str;
     str = "[";
@@ -99,7 +99,6 @@
     str += " ]";
     return str;
 }
-#endif
 
 
 // --- VelocityTracker ---
@@ -133,12 +132,18 @@
         VelocityTracker::Strategy strategy) {
     switch (strategy) {
         case VelocityTracker::Strategy::IMPULSE:
+            if (DEBUG_STRATEGY) {
+                ALOGI("Initializing impulse strategy");
+            }
             return std::make_unique<ImpulseVelocityTrackerStrategy>();
 
         case VelocityTracker::Strategy::LSQ1:
             return std::make_unique<LeastSquaresVelocityTrackerStrategy>(1);
 
         case VelocityTracker::Strategy::LSQ2:
+            if (DEBUG_STRATEGY) {
+                ALOGI("Initializing lsq2 strategy");
+            }
             return std::make_unique<LeastSquaresVelocityTrackerStrategy>(2);
 
         case VelocityTracker::Strategy::LSQ3:
@@ -204,10 +209,10 @@
 
     if ((mCurrentPointerIdBits.value & idBits.value)
             && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) {
-#if DEBUG_VELOCITY
-        ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.",
-                (eventTime - mLastEventTime) * 0.000001f);
-#endif
+        if (DEBUG_VELOCITY) {
+            ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.",
+                  (eventTime - mLastEventTime) * 0.000001f);
+        }
         // We have not received any movements for too long.  Assume that all pointers
         // have stopped.
         mStrategy->clear();
@@ -221,24 +226,24 @@
 
     mStrategy->addMovement(eventTime, idBits, positions);
 
-#if DEBUG_VELOCITY
-    ALOGD("VelocityTracker: addMovement eventTime=%" PRId64 ", idBits=0x%08x, activePointerId=%d",
-            eventTime, idBits.value, mActivePointerId);
-    for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) {
-        uint32_t id = iterBits.firstMarkedBit();
-        uint32_t index = idBits.getIndexOfBit(id);
-        iterBits.clearBit(id);
-        Estimator estimator;
-        getEstimator(id, &estimator);
-        ALOGD("  %d: position (%0.3f, %0.3f), "
-                "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
-                id, positions[index].x, positions[index].y,
-                int(estimator.degree),
-                vectorToString(estimator.xCoeff, estimator.degree + 1).c_str(),
-                vectorToString(estimator.yCoeff, estimator.degree + 1).c_str(),
-                estimator.confidence);
+    if (DEBUG_VELOCITY) {
+        ALOGD("VelocityTracker: addMovement eventTime=%" PRId64
+              ", idBits=0x%08x, activePointerId=%d",
+              eventTime, idBits.value, mActivePointerId);
+        for (BitSet32 iterBits(idBits); !iterBits.isEmpty();) {
+            uint32_t id = iterBits.firstMarkedBit();
+            uint32_t index = idBits.getIndexOfBit(id);
+            iterBits.clearBit(id);
+            Estimator estimator;
+            getEstimator(id, &estimator);
+            ALOGD("  %d: position (%0.3f, %0.3f), "
+                  "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
+                  id, positions[index].x, positions[index].y, int(estimator.degree),
+                  vectorToString(estimator.xCoeff, estimator.degree + 1).c_str(),
+                  vectorToString(estimator.yCoeff, estimator.degree + 1).c_str(),
+                  estimator.confidence);
+        }
     }
-#endif
 }
 
 void VelocityTracker::addMovement(const MotionEvent* event) {
@@ -419,11 +424,10 @@
 static bool solveLeastSquares(const std::vector<float>& x, const std::vector<float>& y,
                               const std::vector<float>& w, uint32_t n, float* outB, float* outDet) {
     const size_t m = x.size();
-#if DEBUG_STRATEGY
-    ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
-            vectorToString(x, m).c_str(), vectorToString(y, m).c_str(),
-            vectorToString(w, m).c_str());
-#endif
+    if (DEBUG_STRATEGY) {
+        ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
+              vectorToString(x).c_str(), vectorToString(y).c_str(), vectorToString(w).c_str());
+    }
     LOG_ALWAYS_FATAL_IF(m != y.size() || m != w.size(), "Mismatched vector sizes");
 
     // Expand the X vector to a matrix A, pre-multiplied by the weights.
@@ -434,9 +438,9 @@
             a[i][h] = a[i - 1][h] * x[h];
         }
     }
-#if DEBUG_STRATEGY
-    ALOGD("  - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str());
-#endif
+    if (DEBUG_STRATEGY) {
+        ALOGD("  - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str());
+    }
 
     // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
     float q[n][m]; // orthonormal basis, column-major order
@@ -455,9 +459,9 @@
         float norm = vectorNorm(&q[j][0], m);
         if (norm < 0.000001f) {
             // vectors are linearly dependent or zero so no solution
-#if DEBUG_STRATEGY
-            ALOGD("  - no solution, norm=%f", norm);
-#endif
+            if (DEBUG_STRATEGY) {
+                ALOGD("  - no solution, norm=%f", norm);
+            }
             return false;
         }
 
@@ -469,22 +473,22 @@
             r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m);
         }
     }
-#if DEBUG_STRATEGY
-    ALOGD("  - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).c_str());
-    ALOGD("  - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).c_str());
+    if (DEBUG_STRATEGY) {
+        ALOGD("  - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).c_str());
+        ALOGD("  - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).c_str());
 
-    // calculate QR, if we factored A correctly then QR should equal A
-    float qr[n][m];
-    for (uint32_t h = 0; h < m; h++) {
-        for (uint32_t i = 0; i < n; i++) {
-            qr[i][h] = 0;
-            for (uint32_t j = 0; j < n; j++) {
-                qr[i][h] += q[j][h] * r[j][i];
+        // calculate QR, if we factored A correctly then QR should equal A
+        float qr[n][m];
+        for (uint32_t h = 0; h < m; h++) {
+            for (uint32_t i = 0; i < n; i++) {
+                qr[i][h] = 0;
+                for (uint32_t j = 0; j < n; j++) {
+                    qr[i][h] += q[j][h] * r[j][i];
+                }
             }
         }
+        ALOGD("  - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).c_str());
     }
-    ALOGD("  - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).c_str());
-#endif
 
     // Solve R B = Qt W Y to find B.  This is easy because R is upper triangular.
     // We just work from bottom-right to top-left calculating B's coefficients.
@@ -500,9 +504,9 @@
         }
         outB[i] /= r[i][i];
     }
-#if DEBUG_STRATEGY
-    ALOGD("  - b=%s", vectorToString(outB, n).c_str());
-#endif
+    if (DEBUG_STRATEGY) {
+        ALOGD("  - b=%s", vectorToString(outB, n).c_str());
+    }
 
     // Calculate the coefficient of determination as 1 - (SSerr / SStot) where
     // SSerr is the residual sum of squares (variance of the error),
@@ -528,11 +532,11 @@
         sstot += w[h] * w[h] * var * var;
     }
     *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1;
-#if DEBUG_STRATEGY
-    ALOGD("  - sserr=%f", sserr);
-    ALOGD("  - sstot=%f", sstot);
-    ALOGD("  - det=%f", *outDet);
-#endif
+    if (DEBUG_STRATEGY) {
+        ALOGD("  - sserr=%f", sserr);
+        ALOGD("  - sstot=%f", sstot);
+        ALOGD("  - det=%f", *outDet);
+    }
     return true;
 }
 
@@ -655,13 +659,11 @@
             outEstimator->time = newestMovement.eventTime;
             outEstimator->degree = degree;
             outEstimator->confidence = xdet * ydet;
-#if DEBUG_STRATEGY
-            ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
-                    int(outEstimator->degree),
-                    vectorToString(outEstimator->xCoeff, n).c_str(),
-                    vectorToString(outEstimator->yCoeff, n).c_str(),
-                    outEstimator->confidence);
-#endif
+            if (DEBUG_STRATEGY) {
+                ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
+                      int(outEstimator->degree), vectorToString(outEstimator->xCoeff, n).c_str(),
+                      vectorToString(outEstimator->yCoeff, n).c_str(), outEstimator->confidence);
+            }
             return true;
         }
     }
@@ -1169,9 +1171,9 @@
     outEstimator->time = newestMovement.eventTime;
     outEstimator->degree = 2; // similar results to 2nd degree fit
     outEstimator->confidence = 1;
-#if DEBUG_STRATEGY
-    ALOGD("velocity: (%f, %f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
-#endif
+    if (DEBUG_STRATEGY) {
+        ALOGD("velocity: (%f, %f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
+    }
     return true;
 }
 
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index caf3a61..1b594f1 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -444,12 +444,19 @@
     ASSERT_EQ(217, event->getToolMinor(0));
     ASSERT_EQ(227, event->getToolMinor(1));
 
-    ASSERT_EQ(18, event->getHistoricalOrientation(0, 0));
-    ASSERT_EQ(28, event->getHistoricalOrientation(1, 0));
-    ASSERT_EQ(118, event->getHistoricalOrientation(0, 1));
-    ASSERT_EQ(128, event->getHistoricalOrientation(1, 1));
-    ASSERT_EQ(218, event->getOrientation(0));
-    ASSERT_EQ(228, event->getOrientation(1));
+    // Calculate the orientation after scaling, keeping in mind that an orientation of 0 is "up",
+    // and the positive y direction is "down".
+    auto toScaledOrientation = [](float angle) {
+        const float x = sinf(angle) * X_SCALE;
+        const float y = -cosf(angle) * Y_SCALE;
+        return atan2f(x, -y);
+    };
+    ASSERT_EQ(toScaledOrientation(18), event->getHistoricalOrientation(0, 0));
+    ASSERT_EQ(toScaledOrientation(28), event->getHistoricalOrientation(1, 0));
+    ASSERT_EQ(toScaledOrientation(118), event->getHistoricalOrientation(0, 1));
+    ASSERT_EQ(toScaledOrientation(128), event->getHistoricalOrientation(1, 1));
+    ASSERT_EQ(toScaledOrientation(218), event->getOrientation(0));
+    ASSERT_EQ(toScaledOrientation(228), event->getOrientation(1));
 }
 
 TEST_F(MotionEventTest, Properties) {
@@ -518,6 +525,7 @@
 TEST_F(MotionEventTest, Scale) {
     MotionEvent event;
     initializeEventWithHistory(&event);
+    const float unscaledOrientation = event.getOrientation(0);
 
     event.scale(2.0f);
 
@@ -534,7 +542,7 @@
     ASSERT_EQ(215 * 2, event.getTouchMinor(0));
     ASSERT_EQ(216 * 2, event.getToolMajor(0));
     ASSERT_EQ(217 * 2, event.getToolMinor(0));
-    ASSERT_EQ(218, event.getOrientation(0));
+    ASSERT_EQ(unscaledOrientation, event.getOrientation(0));
 }
 
 TEST_F(MotionEventTest, Parcel) {
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index d09f2ac..973194c 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -259,7 +259,13 @@
         EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), motionEvent->getTouchMinor(i));
         EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), motionEvent->getToolMajor(i));
         EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), motionEvent->getToolMinor(i));
-        EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), motionEvent->getOrientation(i));
+
+        // Calculate the orientation after scaling, keeping in mind that an orientation of 0 is
+        // "up", and the positive y direction is "down".
+        const float unscaledOrientation = pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
+        const float x = sinf(unscaledOrientation) * xScale;
+        const float y = -cosf(unscaledOrientation) * yScale;
+        EXPECT_EQ(atan2f(x, -y), motionEvent->getOrientation(i));
     }
 
     status = mConsumer->sendFinishedSignal(seq, false);
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 3039362..a87b187 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -343,7 +343,7 @@
         { 235089162955851ns, {{560.66, 843.82}} }, // ACTION_UP
     };
     computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
-                            872.794617);
+                            764.345703);
     computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
                             951.698181);
     computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index a299488..0565f42 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -15,6 +15,13 @@
  */
 
 /**
+ * @defgroup ADataSpace Data Space
+ *
+ * ADataSpace describes how to interpret colors.
+ * @{
+ */
+
+/**
  * @file data_space.h
  */
 
@@ -517,3 +524,5 @@
 __END_DECLS
 
 #endif // ANDROID_DATA_SPACE_H
+
+/** @} */
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 570c7bc..336ff68 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -93,7 +93,7 @@
         "skia/debug/CommonPool.cpp",
         "skia/debug/SkiaCapture.cpp",
         "skia/debug/SkiaMemoryReporter.cpp",
-        "skia/filters/BlurFilter.cpp",
+        "skia/filters/KawaseBlurFilter.cpp",
         "skia/filters/LinearEffect.cpp",
         "skia/filters/StretchShaderFactory.cpp"
     ],
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index d5ec774..e6fb94d 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -53,6 +53,7 @@
 #include "SkBlendMode.h"
 #include "SkImageInfo.h"
 #include "filters/BlurFilter.h"
+#include "filters/KawaseBlurFilter.h"
 #include "filters/LinearEffect.h"
 #include "log/log_main.h"
 #include "skia/debug/SkiaCapture.h"
@@ -328,7 +329,7 @@
 
     if (args.supportsBackgroundBlur) {
         ALOGD("Background Blurs Enabled");
-        mBlurFilter = new BlurFilter();
+        mBlurFilter = new KawaseBlurFilter();
     }
     mCapture = std::make_unique<SkiaCapture>();
 }
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
index 7110018..1beadee 100644
--- a/libs/renderengine/skia/filters/BlurFilter.h
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -27,29 +27,22 @@
 namespace renderengine {
 namespace skia {
 
-/**
- * This is an implementation of a Kawase blur, as described in here:
- * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/
- * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf
- */
 class BlurFilter {
 public:
     // Downsample FBO to improve performance
     static constexpr float kInputScale = 0.25f;
     // Downsample scale factor used to improve performance
     static constexpr float kInverseInputScale = 1.0f / kInputScale;
-    // Maximum number of render passes
-    static constexpr uint32_t kMaxPasses = 4;
     // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited
     // image, up to this radius.
     static constexpr float kMaxCrossFadeRadius = 10.0f;
 
-    explicit BlurFilter();
-    virtual ~BlurFilter(){};
+    explicit BlurFilter(){}
+    virtual ~BlurFilter(){}
 
     // Execute blur, saving it to a texture
-    sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius,
-                            const sk_sp<SkImage> blurInput, const SkRect& blurRect) const;
+    virtual sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius,
+                            const sk_sp<SkImage> blurInput, const SkRect& blurRect) const = 0;
 
     /**
      * Draw the blurred content (from the generate method) into the canvas.
@@ -61,13 +54,10 @@
      * @param blurredImage down-sampled blurred content that was produced by the generate() method
      * @param input original unblurred input that is used to crossfade with the blurredImage
      */
-    void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius,
-                        const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage,
-                        sk_sp<SkImage> input);
-
-private:
-    sk_sp<SkRuntimeEffect> mBlurEffect;
-    sk_sp<SkRuntimeEffect> mMixEffect;
+    virtual void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion,
+                                const uint32_t blurRadius, const float blurAlpha,
+                                const SkRect& blurRect, sk_sp<SkImage> blurredImage,
+                                sk_sp<SkImage> input) = 0;
 };
 
 } // namespace skia
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
similarity index 78%
rename from libs/renderengine/skia/filters/BlurFilter.cpp
rename to libs/renderengine/skia/filters/KawaseBlurFilter.cpp
index 2b6833e..e3a0e58 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include "BlurFilter.h"
+#include "KawaseBlurFilter.h"
 #include <SkCanvas.h>
 #include <SkData.h>
 #include <SkPaint.h>
@@ -32,23 +32,17 @@
 namespace renderengine {
 namespace skia {
 
-BlurFilter::BlurFilter() {
+KawaseBlurFilter::KawaseBlurFilter(): BlurFilter() {
     SkString blurString(R"(
         uniform shader child;
-        uniform float2 in_blurOffset;
-        uniform float2 in_maxSizeXY;
+        uniform float in_blurOffset;
 
         half4 main(float2 xy) {
             half4 c = child.eval(xy);
-            c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
-                                   clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
-            c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
-                                   clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
-            c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
-                                   clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
-            c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
-                                   clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
-
+            c += child.eval(xy + float2(+in_blurOffset, +in_blurOffset));
+            c += child.eval(xy + float2(+in_blurOffset, -in_blurOffset));
+            c += child.eval(xy + float2(-in_blurOffset, -in_blurOffset));
+            c += child.eval(xy + float2(-in_blurOffset, +in_blurOffset));
             return half4(c.rgb * 0.2, 1.0);
         }
     )");
@@ -76,8 +70,9 @@
     mMixEffect = std::move(mixEffect);
 }
 
-sk_sp<SkImage> BlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius,
-                                    const sk_sp<SkImage> input, const SkRect& blurRect) const {
+sk_sp<SkImage> KawaseBlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius,
+                                          const sk_sp<SkImage> input, const SkRect& blurRect)
+    const {
     // Kawase is an approximation of Gaussian, but it behaves differently from it.
     // A radius transformation is required for approximating them, and also to introduce
     // non-integer steps, necessary to smoothly interpolate large radii.
@@ -89,9 +84,6 @@
     SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale),
                                                        std::ceil(blurRect.height() * kInputScale));
 
-    const float stepX = radiusByPasses;
-    const float stepY = radiusByPasses;
-
     // For sampling Skia's API expects the inverse of what logically seems appropriate. In this
     // case you might expect Translate(blurRect.fLeft, blurRect.fTop) X Scale(kInverseInputScale)
     // but instead we must do the inverse.
@@ -103,20 +95,15 @@
     SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
     blurBuilder.child("child") =
             input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix);
-    blurBuilder.uniform("in_blurOffset") = SkV2{stepX * kInputScale, stepY * kInputScale};
-    blurBuilder.uniform("in_maxSizeXY") =
-            SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale};
+    blurBuilder.uniform("in_blurOffset") = radiusByPasses * kInputScale;
 
     sk_sp<SkImage> tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false));
 
     // And now we'll build our chain of scaled blur stages
     for (auto i = 1; i < numberOfPasses; i++) {
-        const float stepScale = (float)i * kInputScale;
         blurBuilder.child("child") =
                 tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
-        blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};
-        blurBuilder.uniform("in_maxSizeXY") =
-                SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale};
+        blurBuilder.uniform("in_blurOffset") = (float) i * radiusByPasses * kInputScale;
         tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false);
     }
 
@@ -139,7 +126,7 @@
     return matrix;
 }
 
-void BlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion,
+void KawaseBlurFilter::drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion,
                                 const uint32_t blurRadius, const float blurAlpha,
                                 const SkRect& blurRect, sk_sp<SkImage> blurredImage,
                                 sk_sp<SkImage> input) {
diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.h b/libs/renderengine/skia/filters/KawaseBlurFilter.h
new file mode 100644
index 0000000..d2731e3
--- /dev/null
+++ b/libs/renderengine/skia/filters/KawaseBlurFilter.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "BlurFilter.h"
+#include <SkCanvas.h>
+#include <SkImage.h>
+#include <SkRuntimeEffect.h>
+#include <SkSurface.h>
+
+using namespace std;
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+/**
+ * This is an implementation of a Kawase blur, as described in here:
+ * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/
+ * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf
+ */
+class KawaseBlurFilter: public BlurFilter {
+public:
+    // Maximum number of render passes
+    static constexpr uint32_t kMaxPasses = 4;
+
+    explicit KawaseBlurFilter();
+    virtual ~KawaseBlurFilter(){}
+
+    // Execute blur, saving it to a texture
+    sk_sp<SkImage> generate(GrRecordingContext* context, const uint32_t radius,
+                            const sk_sp<SkImage> blurInput, const SkRect& blurRect) const override;
+
+    /**
+     * Draw the blurred content (from the generate method) into the canvas.
+     * @param canvas is the destination/output for the blur
+     * @param effectRegion the RoundRect in canvas coordinates that determines the blur coverage
+     * @param blurRadius radius of the blur used to determine the intensity of the crossfade effect
+     * @param blurAlpha alpha value applied to the effectRegion when the blur is drawn
+     * @param blurRect bounds of the blurredImage translated into canvas coordinates
+     * @param blurredImage down-sampled blurred content that was produced by the generate() method
+     * @param input original unblurred input that is used to crossfade with the blurredImage
+     */
+    void drawBlurRegion(SkCanvas* canvas, const SkRRect& effectRegion, const uint32_t blurRadius,
+                        const float blurAlpha, const SkRect& blurRect, sk_sp<SkImage> blurredImage,
+                        sk_sp<SkImage> input) override;
+
+private:
+    sk_sp<SkRuntimeEffect> mBlurEffect;
+    sk_sp<SkRuntimeEffect> mMixEffect;
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/services/inputflinger/dispatcher/EventLogTags.logtags b/services/inputflinger/dispatcher/EventLogTags.logtags
index 2836467..2c5fe21 100644
--- a/services/inputflinger/dispatcher/EventLogTags.logtags
+++ b/services/inputflinger/dispatcher/EventLogTags.logtags
@@ -37,6 +37,7 @@
 
 62000 input_interaction (windows|4)
 62001 input_focus (window|3),(reason|3)
+62003 input_cancel (window|3),(reason|3)
 
 # NOTE - the range 1000000-2000000 is reserved for partners and others who
 # want to define their own log tags without conflicting with the core platform.
\ No newline at end of file
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index ea5799a..176cf89 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -153,6 +153,7 @@
 // Event log tags. See EventLogTags.logtags for reference
 constexpr int LOGTAG_INPUT_INTERACTION = 62000;
 constexpr int LOGTAG_INPUT_FOCUS = 62001;
+constexpr int LOGTAG_INPUT_CANCEL = 62003;
 
 inline nsecs_t now() {
     return systemTime(SYSTEM_TIME_MONOTONIC);
@@ -2077,6 +2078,8 @@
 
         // Handle the case where we did not find a window.
         if (newTouchedWindowHandle == nullptr) {
+            ALOGD("No new touched window at (%" PRId32 ", %" PRId32 ") in display %" PRId32, x, y,
+                  displayId);
             // Try to assign the pointer to the first foreground window we find, if there is one.
             newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle();
         }
@@ -2870,6 +2873,11 @@
             if (!splitMotionEntry) {
                 return; // split event was dropped
             }
+            if (splitMotionEntry->action == AMOTION_EVENT_ACTION_CANCEL) {
+                std::string reason = std::string("reason=pointer cancel on split window");
+                android_log_event_list(LOGTAG_INPUT_CANCEL)
+                        << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS;
+            }
             if (DEBUG_FOCUS) {
                 ALOGD("channel '%s' ~ Split motion event.",
                       connection->getInputChannelName().c_str());
@@ -3575,6 +3583,10 @@
               options.mode);
     }
 
+    std::string reason = std::string("reason=").append(options.reason);
+    android_log_event_list(LOGTAG_INPUT_CANCEL)
+            << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS;
+
     InputTarget target;
     sp<WindowInfoHandle> windowHandle =
             getWindowHandleLocked(connection->inputChannel->getConnectionToken());
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 1879cec..ba0ce95 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -2841,6 +2841,17 @@
     ASSERT_EQ(ui::Transform(), event->getTransform());
 }
 
+TEST_F(InputDispatcherTest, GestureMonitor_NoWindow) {
+    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+    FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
+                                                      true /*isGestureMonitor*/);
+
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
+}
+
 TEST_F(InputDispatcherTest, TestMoveEvent) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =