Merge "Omit DISPLAY_DECORATION layers from CachedSets"
diff --git a/include/input/Input.h b/include/input/Input.h
index f4147a0..55ebb90 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -164,7 +164,7 @@
  * (We want at least 10 but some touch controllers obstensibly configured for 10 pointers
  * will occasionally emit 11.  There is not much harm making this constant bigger.)
  */
-#define MAX_POINTERS 16
+static constexpr size_t MAX_POINTERS = 16;
 
 /*
  * Maximum number of samples supported per motion event.
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index edcb615..5f9a37d 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -500,24 +500,6 @@
     status_t sendTimeline(int32_t inputEventId,
                           std::array<nsecs_t, GraphicsTimeline::SIZE> timeline);
 
-    /* Returns true if there is a deferred event waiting.
-     *
-     * Should be called after calling consume() to determine whether the consumer
-     * has a deferred event to be processed.  Deferred events are somewhat special in
-     * that they have already been removed from the input channel.  If the input channel
-     * becomes empty, the client may need to do extra work to ensure that it processes
-     * the deferred event despite the fact that the input channel's file descriptor
-     * is not readable.
-     *
-     * One option is simply to call consume() in a loop until it returns WOULD_BLOCK.
-     * This guarantees that all deferred events will be processed.
-     *
-     * Alternately, the caller can call hasDeferredEvent() to determine whether there is
-     * a deferred event waiting and then ensure that its event loop wakes up at least
-     * one more time to consume the deferred event.
-     */
-    bool hasDeferredEvent() const;
-
     /* Returns true if there is a pending batch.
      *
      * Should be called after calling consume() with consumeBatches == false to determine
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index a065ce2..6195052 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -1318,10 +1318,6 @@
     return result;
 }
 
-bool InputConsumer::hasDeferredEvent() const {
-    return mMsgDeferred;
-}
-
 bool InputConsumer::hasPendingBatch() const {
     return !mBatches.empty();
 }
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index b6a9476..1c8658b 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -115,12 +115,9 @@
     static_assert(sizeof(InputMessage::Header) == 8);
 }
 
-/**
- * We cannot use the Body::size() method here because it is not static for
- * the Motion type, where "pointerCount" variable affects the size and can change at runtime.
- */
 void TestBodySize() {
     static_assert(sizeof(InputMessage::Body::Key) == 96);
+    static_assert(sizeof(InputMessage::Body::Motion::Pointer) == 136);
     static_assert(sizeof(InputMessage::Body::Motion) ==
                   offsetof(InputMessage::Body::Motion, pointers) +
                           sizeof(InputMessage::Body::Motion::Pointer) * MAX_POINTERS);
@@ -132,6 +129,38 @@
     // Timeline
     static_assert(GraphicsTimeline::SIZE == 2);
     static_assert(sizeof(InputMessage::Body::Timeline) == 24);
+
+    /**
+     * We cannot use the Body::size() method here because it is not static for
+     * the Motion type, where "pointerCount" variable affects the size and can change at runtime.
+     */
+    static_assert(sizeof(InputMessage::Body) ==
+                  offsetof(InputMessage::Body::Motion, pointers) +
+                          sizeof(InputMessage::Body::Motion::Pointer) * MAX_POINTERS);
+    static_assert(sizeof(InputMessage::Body) == 160 + 136 * 16);
+    static_assert(sizeof(InputMessage::Body) == 2336);
+}
+
+/**
+ * In general, we are sending a variable-length message across the socket, because the number of
+ * pointers varies. When we receive the message, we still need to allocate enough memory for the
+ * entire InputMessage struct. This size is, therefore, the worst case scenario. However, it is
+ * still helpful to compute to get an idea of the sizes that are involved.
+ */
+void TestWorstCaseInputMessageSize() {
+    static_assert(sizeof(InputMessage) == /*header*/ 8 + /*body*/ 2336);
+    static_assert(sizeof(InputMessage) == 2344);
+}
+
+/**
+ * Assuming a single pointer, how big is the message that we are sending across the socket?
+ */
+void CalculateSinglePointerInputMessageSize() {
+    constexpr size_t pointerCount = 1;
+    constexpr size_t bodySize = offsetof(InputMessage::Body::Motion, pointers) +
+            sizeof(InputMessage::Body::Motion::Pointer) * pointerCount;
+    static_assert(bodySize == 160 + 136);
+    static_assert(bodySize == 296); // For the total message size, add the small header
 }
 
 // --- VerifiedInputEvent ---
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 063ce67..763b82d 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -1104,6 +1104,15 @@
                 paint.setDither(true);
             }
             paint.setAlphaf(layer.alpha);
+
+            if (imageTextureRef->colorType() == kAlpha_8_SkColorType) {
+                LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with A8");
+                float matrix[] = { 0, 0, 0, 0, 0,
+                                   0, 0, 0, 0, 0,
+                                   0, 0, 0, 0, 0,
+                                   0, 0, 0, -1, 1 };
+                paint.setColorFilter(SkColorFilters::Matrix(matrix));
+            }
         } else {
             ATRACE_NAME("DrawColor");
             const auto color = layer.source.solidColor;
@@ -1125,7 +1134,11 @@
             paint.setBlendMode(SkBlendMode::kSrc);
         }
 
-        paint.setColorFilter(displayColorTransform);
+        // A color filter will have been set for an A8 buffer. Do not replace
+        // it with the displayColorTransform, which shouldn't affect A8.
+        if (!paint.getColorFilter()) {
+            paint.setColorFilter(displayColorTransform);
+        }
 
         if (!roundRectClip.isEmpty()) {
             canvas->clipRRect(roundRectClip, true);
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 2a25b0b..612a0aa 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -218,14 +218,35 @@
         uint8_t* pixels;
         buffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
                                   reinterpret_cast<void**>(&pixels));
-        pixels[0] = color.r;
-        pixels[1] = color.g;
-        pixels[2] = color.b;
-        pixels[3] = color.a;
+        for (uint32_t j = 0; j < height; j++) {
+            uint8_t* dst = pixels + (buffer->getBuffer()->getStride() * j * 4);
+            for (uint32_t i = 0; i < width; i++) {
+                dst[0] = color.r;
+                dst[1] = color.g;
+                dst[2] = color.b;
+                dst[3] = color.a;
+                dst += 4;
+            }
+        }
         buffer->getBuffer()->unlock();
         return buffer;
     }
 
+    std::shared_ptr<renderengine::ExternalTexture> allocateR8Buffer(int width, int height) {
+        auto buffer = new GraphicBuffer(width, height, android::PIXEL_FORMAT_R_8, 1,
+                                        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+                                                GRALLOC_USAGE_HW_TEXTURE,
+                                        "r8");
+        if (buffer->initCheck() != 0) {
+            // Devices are not required to support R8.
+            return nullptr;
+        }
+        return std::make_shared<
+                renderengine::impl::ExternalTexture>(std::move(buffer), *mRE,
+                                                     renderengine::impl::ExternalTexture::Usage::
+                                                             READABLE);
+    }
+
     RenderEngineTest() {
         const ::testing::TestInfo* const test_info =
                 ::testing::UnitTest::GetInstance()->current_test_info();
@@ -2541,6 +2562,66 @@
 
     expectBufferColor(Rect(kGreyLevels, 1), generator, 2);
 }
+
+TEST_P(RenderEngineTest, r8_behaves_as_mask) {
+    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+        return;
+    }
+
+    initializeRenderEngine();
+
+    const auto r8Buffer = allocateR8Buffer(2, 1);
+    if (!r8Buffer) {
+        return;
+    }
+    {
+        uint8_t* pixels;
+        r8Buffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                    reinterpret_cast<void**>(&pixels));
+        // This will be drawn on top of a green buffer. We'll verify that 255
+        // results in keeping the original green and 0 results in black.
+        pixels[0] = 0;
+        pixels[1] = 255;
+        r8Buffer->getBuffer()->unlock();
+    }
+
+    const auto rect = Rect(0, 0, 2, 1);
+    const renderengine::DisplaySettings display{
+            .physicalDisplay = rect,
+            .clip = rect,
+            .outputDataspace = ui::Dataspace::SRGB,
+    };
+
+    const auto greenBuffer = allocateAndFillSourceBuffer(2, 1, ubyte4(0, 255, 0, 255));
+    const renderengine::LayerSettings greenLayer{
+            .geometry.boundaries = rect.toFloatRect(),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = greenBuffer,
+                                    },
+                    },
+            .alpha = 1.0f,
+    };
+    const renderengine::LayerSettings r8Layer{
+            .geometry.boundaries = rect.toFloatRect(),
+            .source =
+                    renderengine::PixelSource{
+                            .buffer =
+                                    renderengine::Buffer{
+                                            .buffer = r8Buffer,
+                                    },
+                    },
+            .alpha = 1.0f,
+    };
+
+    std::vector<renderengine::LayerSettings> layers{greenLayer, r8Layer};
+    invokeDraw(display, layers);
+
+    expectBufferColor(Rect(0, 0, 1, 1), 0,   0, 0, 255);
+    expectBufferColor(Rect(1, 0, 2, 1), 0, 255, 0, 255);
+}
 } // namespace renderengine
 } // namespace android
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 441a1de..7a3d6c5 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -215,7 +215,7 @@
         return false;
     }
     if (pointerCount < 1 || pointerCount > MAX_POINTERS) {
-        ALOGE("Motion event has invalid pointer count %zu; value must be between 1 and %d.",
+        ALOGE("Motion event has invalid pointer count %zu; value must be between 1 and %zu.",
               pointerCount, MAX_POINTERS);
         return false;
     }
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index 4bd1cd8..ff3a592 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -282,7 +282,7 @@
 
         if (outCount >= MAX_POINTERS) {
             if (DEBUG_POINTERS) {
-                ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
+                ALOGD("MultiTouch device %s emitted more than maximum of %zu pointers; "
                       "ignoring the rest.",
                       getDeviceName().c_str(), MAX_POINTERS);
             }
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 0814bc2..aa2f832 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -558,7 +558,7 @@
     MotionEvent event;
     PointerProperties pointerProperties[MAX_POINTERS + 1];
     PointerCoords pointerCoords[MAX_POINTERS + 1];
-    for (int i = 0; i <= MAX_POINTERS; i++) {
+    for (size_t i = 0; i <= MAX_POINTERS; i++) {
         pointerProperties[i].clear();
         pointerProperties[i].id = i;
         pointerCoords[i].clear();