Merge "Implement bufferInfo handle packing logic"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8a05c43..47c4f62 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1701,7 +1701,7 @@
     printf("*** See dumpstate-board.txt entry ***\n");
 }
 
-static void ShowUsageAndExit(int exit_code = 1) {
+static void ShowUsage() {
     fprintf(stderr,
             "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
             "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
@@ -1721,12 +1721,6 @@
             "  -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
             "shouldn't be used with -P)\n"
             "  -v: prints the dumpstate header and exit\n");
-    exit(exit_code);
-}
-
-static void ExitOnInvalidArgs() {
-    fprintf(stderr, "invalid combination of args\n");
-    ShowUsageAndExit();
 }
 
 static void register_sig_handler() {
@@ -2523,17 +2517,18 @@
 
     switch (status) {
         case Dumpstate::RunStatus::OK:
-            return 0;
-            // TODO(b/111441001): Exit directly in the following cases.
+            exit(0);
         case Dumpstate::RunStatus::HELP:
-            ShowUsageAndExit(0 /* exit code */);
-            break;
+            ShowUsage();
+            exit(0);
         case Dumpstate::RunStatus::INVALID_INPUT:
-            ExitOnInvalidArgs();
-            break;
+            fprintf(stderr, "Invalid combination of args\n");
+            ShowUsage();
+            exit(1);
         case Dumpstate::RunStatus::ERROR:
-            exit(-1);
-            break;
+            exit(2);
+        default:
+            fprintf(stderr, "Unknown status: %d\n", status);
+            exit(2);
     }
-    return 0;
 }
diff --git a/include/input/Input.h b/include/input/Input.h
index 037270c..2c4a511 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -220,6 +220,27 @@
     POLICY_FLAG_PASS_TO_USER = 0x40000000,
 };
 
+/**
+ * Classifications of the current gesture, if available.
+ *
+ * The following values must be kept in sync with MotionEvent.java
+ */
+enum class MotionClassification : uint8_t {
+    /**
+     * No classification is available.
+     */
+    NONE = 0,
+    /**
+     * Too early to classify the current gesture. Need more events. Look for changes in the
+     * upcoming motion events.
+     */
+    AMBIGUOUS_GESTURE = 1,
+    /**
+     * The current gesture likely represents a user intentionally exerting force on the touchscreen.
+     */
+    DEEP_PRESS = 2,
+};
+
 /*
  * Pointer coordinate data.
  */
@@ -419,6 +440,8 @@
 
     inline void setButtonState(int32_t buttonState) { mButtonState = buttonState; }
 
+    inline MotionClassification getClassification() const { return mClassification; }
+
     inline int32_t getActionButton() const { return mActionButton; }
 
     inline void setActionButton(int32_t button) { mActionButton = button; }
@@ -582,6 +605,7 @@
             int32_t edgeFlags,
             int32_t metaState,
             int32_t buttonState,
+            MotionClassification classification,
             float xOffset,
             float yOffset,
             float xPrecision,
@@ -635,6 +659,7 @@
     int32_t mEdgeFlags;
     int32_t mMetaState;
     int32_t mButtonState;
+    MotionClassification mClassification;
     float mXOffset;
     float mYOffset;
     float mXPrecision;
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 1b69dfd..05655c1 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -23,7 +23,11 @@
         "include_apex",
     ],
 
-    cflags: ["-Wall", "-Wextra", "-Werror"],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
 
     srcs: [
         "ibinder.cpp",
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index ee7132f..f0d25f7 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -87,6 +87,11 @@
     AStatus_getStatus;
     AStatus_isOk;
     AStatus_newOk;
+    ABinderProcess_joinThreadPool; # apex
+    ABinderProcess_setThreadPoolMaxThreadCount; # apex
+    ABinderProcess_startThreadPool; # apex
+    AServiceManager_addService; # apex
+    AServiceManager_getService; # apex
   local:
     *;
 };
diff --git a/libs/binder/ndk/scripts/init_map.sh b/libs/binder/ndk/scripts/init_map.sh
index 1f74e43..3529b72 100755
--- a/libs/binder/ndk/scripts/init_map.sh
+++ b/libs/binder/ndk/scripts/init_map.sh
@@ -10,6 +10,10 @@
     grep -oP "AParcel_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_parcel.h;
     grep -oP "AStatus_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_status.h;
 } | sort | uniq | awk '{ print "    " $0 ";"; }'
+{
+    grep -oP "AServiceManager_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_manager.h;
+    grep -oP "ABinderProcess_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_process.h;
+} | sort | uniq | awk '{ print "    " $0 "; # apex"; }'
 echo "  local:"
 echo "    *;"
 echo "};"
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 369f523..928ef95 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -31,6 +31,7 @@
 
 enum class Tag : uint32_t {
     CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
+    CREATE_WITH_SURFACE_PARENT,
     CLEAR_LAYER_FRAME_STATS,
     GET_LAYER_FRAME_STATS,
     LAST = GET_LAYER_FRAME_STATS,
@@ -56,6 +57,18 @@
                                                                             handle, gbp);
     }
 
+    status_t createWithSurfaceParent(const String8& name, uint32_t width, uint32_t height,
+                                     PixelFormat format, uint32_t flags,
+                                     const sp<IGraphicBufferProducer>& parent, int32_t windowType,
+                                     int32_t ownerUid, sp<IBinder>* handle,
+                                     sp<IGraphicBufferProducer>* gbp) override {
+        return callRemote<decltype(
+                &ISurfaceComposerClient::createWithSurfaceParent)>(Tag::CREATE_WITH_SURFACE_PARENT,
+                                                                   name, width, height, format,
+                                                                   flags, parent, windowType,
+                                                                   ownerUid, handle, gbp);
+    }
+
     status_t clearLayerFrameStats(const sp<IBinder>& handle) const override {
         return callRemote<decltype(
                 &ISurfaceComposerClient::clearLayerFrameStats)>(Tag::CLEAR_LAYER_FRAME_STATS,
@@ -86,6 +99,8 @@
     switch (tag) {
         case Tag::CREATE_SURFACE:
             return callLocal(data, reply, &ISurfaceComposerClient::createSurface);
+        case Tag::CREATE_WITH_SURFACE_PARENT:
+            return callLocal(data, reply, &ISurfaceComposerClient::createWithSurfaceParent);
         case Tag::CLEAR_LAYER_FRAME_STATS:
             return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
         case Tag::GET_LAYER_FRAME_STATS:
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 6c39d6f..8b9e4d7 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -977,6 +977,29 @@
     return s;
 }
 
+sp<SurfaceControl> SurfaceComposerClient::createWithSurfaceParent(const String8& name, uint32_t w,
+                                                                  uint32_t h, PixelFormat format,
+                                                                  uint32_t flags, Surface* parent,
+                                                                  int32_t windowType,
+                                                                  int32_t ownerUid) {
+    sp<SurfaceControl> sur;
+    status_t err = mStatus;
+
+    if (mStatus == NO_ERROR) {
+        sp<IBinder> handle;
+        sp<IGraphicBufferProducer> parentGbp = parent->getIGraphicBufferProducer();
+        sp<IGraphicBufferProducer> gbp;
+
+        err = mClient->createWithSurfaceParent(name, w, h, format, flags, parentGbp, windowType,
+                                               ownerUid, &handle, &gbp);
+        ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err));
+        if (err == NO_ERROR) {
+            return new SurfaceControl(this, handle, gbp, true /* owned */);
+        }
+    }
+    return nullptr;
+}
+
 status_t SurfaceComposerClient::createSurfaceChecked(
         const String8& name,
         uint32_t w,
@@ -1132,6 +1155,7 @@
     return ComposerService::getComposerService()->getDisplayedContentSample(display, maxFrames,
                                                                             timestamp, outStats);
 }
+
 // ----------------------------------------------------------------------------
 
 status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 56ca197..f443df8 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -58,6 +58,16 @@
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
      */
+    virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
+                                             PixelFormat format, uint32_t flags,
+                                             const sp<IGraphicBufferProducer>& parent,
+                                             int32_t windowType, int32_t ownerUid,
+                                             sp<IBinder>* handle,
+                                             sp<IGraphicBufferProducer>* gbp) = 0;
+
+    /*
+     * Requires ACCESS_SURFACE_FLINGER permission
+     */
     virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const = 0;
 
     /*
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e0cbb70..f16f781 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -168,15 +168,27 @@
     );
 
     status_t createSurfaceChecked(
-            const String8& name,// name of the surface
-            uint32_t w,         // width in pixel
-            uint32_t h,         // height in pixel
-            PixelFormat format, // pixel-format desired
+            const String8& name, // name of the surface
+            uint32_t w,          // width in pixel
+            uint32_t h,          // height in pixel
+            PixelFormat format,  // pixel-format desired
             sp<SurfaceControl>* outSurface,
-            uint32_t flags = 0, // usage flags
+            uint32_t flags = 0,               // usage flags
             SurfaceControl* parent = nullptr, // parent
             int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
-            int32_t ownerUid = -1 // UID of the task
+            int32_t ownerUid = -1    // UID of the task
+    );
+
+    //! Create a surface
+    sp<SurfaceControl> createWithSurfaceParent(
+            const String8& name,       // name of the surface
+            uint32_t w,                // width in pixel
+            uint32_t h,                // height in pixel
+            PixelFormat format,        // pixel-format desired
+            uint32_t flags = 0,        // usage flags
+            Surface* parent = nullptr, // parent
+            int32_t windowType = -1,   // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
+            int32_t ownerUid = -1      // UID of the task
     );
 
     //! Create a virtual display
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index a558970..db86c8e 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -234,6 +234,7 @@
         int32_t edgeFlags,
         int32_t metaState,
         int32_t buttonState,
+        MotionClassification classification,
         float xOffset,
         float yOffset,
         float xPrecision,
@@ -250,6 +251,7 @@
     mEdgeFlags = edgeFlags;
     mMetaState = metaState;
     mButtonState = buttonState;
+    mClassification = classification;
     mXOffset = xOffset;
     mYOffset = yOffset;
     mXPrecision = xPrecision;
@@ -270,6 +272,7 @@
     mEdgeFlags = other->mEdgeFlags;
     mMetaState = other->mMetaState;
     mButtonState = other->mButtonState;
+    mClassification = other->mClassification;
     mXOffset = other->mXOffset;
     mYOffset = other->mYOffset;
     mXPrecision = other->mXPrecision;
@@ -451,6 +454,7 @@
     mEdgeFlags = parcel->readInt32();
     mMetaState = parcel->readInt32();
     mButtonState = parcel->readInt32();
+    mClassification = static_cast<MotionClassification>(parcel->readByte());
     mXOffset = parcel->readFloat();
     mYOffset = parcel->readFloat();
     mXPrecision = parcel->readFloat();
@@ -501,6 +505,7 @@
     parcel->writeInt32(mEdgeFlags);
     parcel->writeInt32(mMetaState);
     parcel->writeInt32(mButtonState);
+    parcel->writeByte(static_cast<int8_t>(mClassification));
     parcel->writeFloat(mXOffset);
     parcel->writeFloat(mYOffset);
     parcel->writeFloat(mXPrecision);
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index f33b210..0ddee44 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -1112,6 +1112,7 @@
             msg->body.motion.edgeFlags,
             msg->body.motion.metaState,
             msg->body.motion.buttonState,
+            MotionClassification::NONE,
             msg->body.motion.xOffset,
             msg->body.motion.yOffset,
             msg->body.motion.xPrecision,
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 99f83ba..e4c1514 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -260,7 +260,7 @@
     event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0,
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
             AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
-            X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
+            MotionClassification::NONE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
             ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
             2, pointerProperties, pointerCoords);
 
@@ -572,8 +572,11 @@
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
     }
     MotionEvent event;
-    event.initialize(0, 0, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
+    event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
+            0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE,
+            AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+            0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
+            0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
     float originalRawX = 0 + 3;
     float originalRawY = -RADIUS + 2;
 
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index af97c34..3c67542 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -90,7 +90,8 @@
 
     MotionEvent* event = new MotionEvent();
     PointerCoords coords;
-    PointerProperties properties[1];
+    constexpr size_t pointerCount = 1;
+    PointerProperties properties[pointerCount];
 
     properties[0].id = DEFAULT_POINTER_ID;
     properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
@@ -98,8 +99,11 @@
     // First sample added separately with initialize
     coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x);
     coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y);
-    event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, positions[0].time, 1, properties, &coords);
+    event->initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/,
+            AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+            0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
+            0 /*downTime*/, positions[0].time, pointerCount, properties, &coords);
 
     for (size_t i = 1; i < numSamples; i++) {
         coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[i].x);
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 18c3ded..cf9d3c7 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -40,6 +40,7 @@
 #include <hardware_legacy/power.h>
 
 #include <android-base/stringprintf.h>
+#include <cutils/properties.h>
 #include <openssl/sha.h>
 #include <utils/Log.h>
 #include <utils/Timers.h>
@@ -108,6 +109,19 @@
     return strstr(name, "v4l-touch") == name;
 }
 
+/**
+ * Returns true if V4L devices should be scanned.
+ *
+ * The system property ro.input.video_enabled can be used to control whether
+ * EventHub scans and opens V4L devices. As V4L does not support multiple
+ * clients, EventHub effectively blocks access to these devices when it opens
+ * them. This property enables other clients to read these devices for testing
+ * and development.
+ */
+static bool isV4lScanningEnabled() {
+  return property_get_bool("ro.input.video_enabled", true /* default_value */);
+}
+
 static nsecs_t processEventTimestamp(const struct input_event& event) {
     // Use the time specified in the event instead of the current time
     // so that downstream code can get more accurate estimates of
@@ -237,9 +251,14 @@
     mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
     LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s",
             DEVICE_PATH, strerror(errno));
-    mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
-    LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
-            VIDEO_DEVICE_PATH, strerror(errno));
+    if (isV4lScanningEnabled()) {
+        mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
+        LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
+                VIDEO_DEVICE_PATH, strerror(errno));
+    } else {
+        mVideoWd = -1;
+        ALOGI("Video device scanning disabled");
+    }
 
     struct epoll_event eventItem;
     memset(&eventItem, 0, sizeof(eventItem));
@@ -1056,9 +1075,11 @@
     if(result < 0) {
         ALOGE("scan dir failed for %s", DEVICE_PATH);
     }
-    result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
-    if (result != OK) {
-        ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
+    if (isV4lScanningEnabled()) {
+        result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
+        if (result != OK) {
+            ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
+        }
     }
     if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {
         createVirtualKeyboardLocked();
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 7997928..0bde5fd 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2691,7 +2691,7 @@
             event.initialize(args->deviceId, args->source, args->displayId,
                     args->action, args->actionButton,
                     args->flags, args->edgeFlags, args->metaState, args->buttonState,
-                    0, 0, args->xPrecision, args->yPrecision,
+                    args->classification, 0, 0, args->xPrecision, args->yPrecision,
                     args->downTime, args->eventTime,
                     args->pointerCount, args->pointerProperties, args->pointerCoords);
 
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index b4eb370..b349c73 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -71,8 +71,8 @@
 NotifyMotionArgs::NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId,
         uint32_t source, int32_t displayId, uint32_t policyFlags,
         int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
-        int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp,
-        uint32_t pointerCount,
+        int32_t buttonState, MotionClassification classification,
+        int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
         float xPrecision, float yPrecision, nsecs_t downTime,
         const std::vector<TouchVideoFrame>& videoFrames) :
@@ -80,7 +80,7 @@
         displayId(displayId), policyFlags(policyFlags),
         action(action), actionButton(actionButton),
         flags(flags), metaState(metaState), buttonState(buttonState),
-        edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
+        classification(classification), edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
         pointerCount(pointerCount),
         xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime),
         videoFrames(videoFrames) {
@@ -95,7 +95,7 @@
         source(other.source), displayId(other.displayId), policyFlags(other.policyFlags),
         action(other.action), actionButton(other.actionButton), flags(other.flags),
         metaState(other.metaState), buttonState(other.buttonState),
-        edgeFlags(other.edgeFlags),
+        classification(other.classification), edgeFlags(other.edgeFlags),
         deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount),
         xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime),
         videoFrames(other.videoFrames) {
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 33bf163..2b31f6e 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2834,7 +2834,8 @@
                 NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                         mSource, displayId, policyFlags,
                         AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
-                        metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                        metaState, buttonState,
+                        MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                         /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                         mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
                 getListener()->notifyMotion(&releaseArgs);
@@ -2843,7 +2844,7 @@
 
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
                 displayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState,
-                AMOTION_EVENT_EDGE_FLAG_NONE,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
@@ -2855,7 +2856,8 @@
                 buttonState |= actionButton;
                 NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                         mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS,
-                        actionButton, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                        actionButton, 0, metaState, buttonState,
+                        MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                         /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                         mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
                 getListener()->notifyMotion(&pressArgs);
@@ -2869,7 +2871,8 @@
                 && (mSource == AINPUT_SOURCE_MOUSE)) {
             NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
-                    metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                    metaState, currentButtonState,
+                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                     /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
             getListener()->notifyMotion(&hoverArgs);
@@ -2883,7 +2886,7 @@
             NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags,
                     AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
-                    AMOTION_EVENT_EDGE_FLAG_NONE,
+                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                     /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
             getListener()->notifyMotion(&scrollArgs);
@@ -3014,8 +3017,8 @@
 
         NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, 0,
-                AMOTION_EVENT_EDGE_FLAG_NONE,
+                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, /* buttonState */ 0,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 0, 0, 0, /* videoFrames */ {});
         getListener()->notifyMotion(&scrollArgs);
@@ -5413,7 +5416,7 @@
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
-                metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                 /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 0, 0, mPointerGesture.downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
@@ -6338,8 +6341,8 @@
         // Send up.
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6352,8 +6355,8 @@
         // Send hover exit.
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6368,7 +6371,8 @@
             // Send down.
             NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags,
-                    AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
+                    AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState,
+                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
                     /* deviceTimestamp */ 0,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
@@ -6379,8 +6383,8 @@
         // Send move.
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6395,8 +6399,8 @@
             NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                     mSource, displayId, policyFlags,
                     AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
-                    mCurrentRawState.buttonState, 0,
-                    /* deviceTimestamp */ 0,
+                    mCurrentRawState.buttonState, MotionClassification::NONE,
+                    AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
                     mPointerSimple.downTime, /* videoFrames */ {});
@@ -6407,8 +6411,8 @@
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
-                mCurrentRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                mCurrentRawState.buttonState, MotionClassification::NONE,
+                AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6429,8 +6433,8 @@
 
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
                 mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                /* deviceTimestamp */ 0,
+                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState,
+                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &pointerCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime, /* videoFrames */ {});
@@ -6497,8 +6501,8 @@
     std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId);
     NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId,
             source, displayId, policyFlags,
-            action, actionButton, flags, metaState, buttonState, edgeFlags,
-            deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
+            action, actionButton, flags, metaState, buttonState, MotionClassification::NONE,
+            edgeFlags, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
             xPrecision, yPrecision, downTime, std::move(frames));
     getListener()->notifyMotion(&args);
 }
@@ -7422,9 +7426,9 @@
 
     NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
             AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags,
-            AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-            /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
-            0, 0, 0, /* videoFrames */ {});
+            AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, MotionClassification::NONE,
+            AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
+            &pointerProperties, &pointerCoords, 0, 0, 0, /* videoFrames */ {});
     getListener()->notifyMotion(&args);
 }
 
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 2442cc0..53247a0 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -99,6 +99,10 @@
     int32_t flags;
     int32_t metaState;
     int32_t buttonState;
+    /**
+     * Classification of the current touch gesture
+     */
+    MotionClassification classification;
     int32_t edgeFlags;
     /**
      * A timestamp in the input device's time base, not the platform's.
@@ -120,7 +124,7 @@
     NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
             int32_t displayId, uint32_t policyFlags,
             int32_t action, int32_t actionButton, int32_t flags,
-            int32_t metaState, int32_t buttonState,
+            int32_t metaState, int32_t buttonState, MotionClassification classification,
             int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
             const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime,
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 26f01b7..704c13a 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -160,70 +160,70 @@
         pointerCoords[i].clear();
     }
 
+    // Some constants commonly used below
+    constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+    constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
+    constexpr int32_t metaState = AMETA_NONE;
+    constexpr MotionClassification classification = MotionClassification::NONE;
+
     // Rejects undefined motion actions.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            /*action*/ -1, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with undefined action.";
 
     // Rejects pointer down with invalid index.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer down index too large.";
 
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer down index too small.";
 
     // Rejects pointer up with invalid index.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer up index too large.";
 
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer up index too small.";
 
     // Rejects motion events with invalid number of pointers.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 0, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with 0 pointers.";
 
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -233,20 +233,18 @@
 
     // Rejects motion events with invalid pointer ids.
     pointerProperties[0].id = -1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer ids less than 0.";
 
     pointerProperties[0].id = MAX_POINTER_ID + 1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 1, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -255,10 +253,9 @@
     // Rejects motion events with duplicate pointer ids.
     pointerProperties[0].id = 1;
     pointerProperties[1].id = 1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ 2, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -460,7 +457,8 @@
     // Define a valid motion down event.
     event.initialize(DEVICE_ID, source, displayId,
             AMOTION_EVENT_ACTION_DOWN, /* actionButton */0, /* flags */ 0, /* edgeFlags */ 0,
-            AMETA_NONE, /* buttonState */ 0, /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
+            AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
+            /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
             /* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties,
             pointerCoords);
 
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 9b2cd50..189ae36 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -35,6 +35,7 @@
 using namespace android::hardware::sensors::V1_0::implementation;
 using android::hardware::sensors::V2_0::ISensorsCallback;
 using android::hardware::sensors::V2_0::EventQueueFlagBits;
+using android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
 using android::hardware::hidl_vec;
 using android::hardware::Return;
 using android::SensorDeviceUtils::HidlServiceRegistrationWaiter;
@@ -94,6 +95,8 @@
 SensorDevice::SensorDevice()
         : mHidlTransportErrors(20),
           mRestartWaiter(new HidlServiceRegistrationWaiter()),
+          mEventQueueFlag(nullptr),
+          mWakeLockQueueFlag(nullptr),
           mReconnecting(false) {
     if (!connectHidlService()) {
         return;
@@ -137,6 +140,11 @@
         hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
         mEventQueueFlag = nullptr;
     }
+
+    if (mWakeLockQueueFlag != nullptr) {
+        hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
+        mWakeLockQueueFlag = nullptr;
+    }
 }
 
 bool SensorDevice::connectHidlService() {
@@ -198,10 +206,16 @@
                 SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT,
                 true /* configureEventFlagWord */);
 
+        hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
         hardware::EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag);
 
+        hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
+        hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(),
+                                             &mWakeLockQueueFlag);
+
         CHECK(mSensors != nullptr && mEventQueue != nullptr &&
-                mWakeLockQueue != nullptr && mEventQueueFlag != nullptr);
+                mWakeLockQueue != nullptr && mEventQueueFlag != nullptr &&
+                mWakeLockQueueFlag != nullptr);
 
         status_t status = StatusFromResult(checkReturn(mSensors->initialize(
                 *mEventQueue->getDesc(),
@@ -512,9 +526,12 @@
 }
 
 void SensorDevice::writeWakeLockHandled(uint32_t count) {
-    if (mSensors != nullptr && mSensors->supportsMessageQueues() &&
-            !mWakeLockQueue->write(&count)) {
-        ALOGW("Failed to write wake lock handled");
+    if (mSensors != nullptr && mSensors->supportsMessageQueues()) {
+        if (mWakeLockQueue->write(&count)) {
+            mWakeLockQueueFlag->wake(asBaseType(WakeLockQueueFlagBits::DATA_WRITTEN));
+        } else {
+            ALOGW("Failed to write wake lock handled");
+        }
     }
 }
 
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index e1024ac..2a69654 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -238,6 +238,7 @@
     std::unique_ptr<WakeLockQueue> mWakeLockQueue;
 
     hardware::EventFlag* mEventQueueFlag;
+    hardware::EventFlag* mWakeLockQueueFlag;
 
     std::array<Event, SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
 
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 4e4d7dd..4eafeac 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -176,7 +176,7 @@
 
     if (!blackOutLayer) {
         // TODO: we could be more subtle with isFixedSize()
-        const bool useFiltering = needsFiltering(renderArea) || isFixedSize();
+        const bool useFiltering = needsFiltering() || renderArea.needsFiltering() || isFixedSize();
 
         // Query the texture matrix given our current filtering mode.
         float textureMatrix[16];
@@ -597,8 +597,11 @@
     return true;
 }
 
-bool BufferLayer::needsFiltering(const RenderArea& renderArea) const {
-    return mNeedsFiltering || renderArea.needsFiltering();
+bool BufferLayer::needsFiltering() const {
+    const auto displayFrame = getBE().compositionInfo.hwc.displayFrame;
+    const auto sourceCrop = getBE().compositionInfo.hwc.sourceCrop;
+    return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() ||
+            sourceCrop.getWidth() != displayFrame.getWidth();
 }
 
 void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
@@ -623,7 +626,6 @@
      */
     const Rect bounds{computeBounds()}; // Rounds from FloatRect
 
-    ui::Transform t = getTransform();
     Rect win = bounds;
     const int bufferWidth = getBufferSize(s).getWidth();
     const int bufferHeight = getBufferSize(s).getHeight();
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index be16cf5..6eda20d 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -168,8 +168,8 @@
     const uint32_t mTextureName;
 
 private:
-    // needsLinearFiltering - true if this surface's state requires filtering
-    bool needsFiltering(const RenderArea& renderArea) const;
+    // Returns true if this layer requires filtering
+    bool needsFiltering() const;
 
     // drawing
     void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const;
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 4f6fb1c..0e447d8 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -95,6 +95,26 @@
                                  ownerUid, handle, gbp, &parent);
 }
 
+status_t Client::createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
+                                         PixelFormat format, uint32_t flags,
+                                         const sp<IGraphicBufferProducer>& parent,
+                                         int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
+                                         sp<IGraphicBufferProducer>* gbp) {
+    if (mFlinger->authenticateSurfaceTexture(parent) == false) {
+        return BAD_VALUE;
+    }
+
+    const auto& layer = (static_cast<MonitoredProducer*>(parent.get()))->getLayer();
+    if (layer == nullptr) {
+        return BAD_VALUE;
+    }
+
+    sp<IBinder> parentHandle = layer->getHandle();
+
+    return createSurface(name, w, h, format, flags, parentHandle, windowType, ownerUid, handle,
+                         gbp);
+}
+
 status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
     sp<Layer> layer = getLayerUser(handle);
     if (layer == nullptr) {
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index d0051de..0f5ee4c 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -58,6 +58,12 @@
             sp<IBinder>* handle,
             sp<IGraphicBufferProducer>* gbp);
 
+    virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
+                                             PixelFormat format, uint32_t flags,
+                                             const sp<IGraphicBufferProducer>& parent,
+                                             int32_t windowType, int32_t ownerUid,
+                                             sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp);
+
     virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
 
     virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;