Merge "Fix race condition clearing VSYNC enable on VrFlinger startup." into oc-dr1-dev
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index f31bcea..efa1ffb 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -65,6 +65,7 @@
             nsecs_t eventTime __attribute__((aligned(8)));
             int32_t deviceId;
             int32_t source;
+            int32_t displayId;
             int32_t action;
             int32_t flags;
             int32_t keyCode;
@@ -83,6 +84,7 @@
             nsecs_t eventTime __attribute__((aligned(8)));
             int32_t deviceId;
             int32_t source;
+            int32_t displayId;
             int32_t action;
             int32_t actionButton;
             int32_t flags;
@@ -232,6 +234,7 @@
             uint32_t seq,
             int32_t deviceId,
             int32_t source,
+            int32_t displayId,
             int32_t action,
             int32_t actionButton,
             int32_t flags,
@@ -303,7 +306,7 @@
      * Other errors probably indicate that the channel is broken.
      */
     status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
-            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
+            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
 
     /* Sends a finished signal to the publisher to inform it that the message
      * with the specified sequence number has finished being process and whether
@@ -424,9 +427,10 @@
     Vector<SeqChain> mSeqChains;
 
     status_t consumeBatch(InputEventFactoryInterface* factory,
-            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
+            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
     status_t consumeSamples(InputEventFactoryInterface* factory,
-            Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent);
+            Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent,
+            int32_t* displayId);
 
     void updateTouchState(InputMessage* msg);
     void rewriteMessage(const TouchState& state, InputMessage* msg);
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 293bc25..d5c5927 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -285,6 +285,7 @@
         uint32_t seq,
         int32_t deviceId,
         int32_t source,
+        int32_t displayId,
         int32_t action,
         int32_t actionButton,
         int32_t flags,
@@ -327,6 +328,7 @@
     msg.body.motion.seq = seq;
     msg.body.motion.deviceId = deviceId;
     msg.body.motion.source = source;
+    msg.body.motion.displayId = displayId;
     msg.body.motion.action = action;
     msg.body.motion.actionButton = actionButton;
     msg.body.motion.flags = flags;
@@ -396,7 +398,8 @@
 }
 
 status_t InputConsumer::consume(InputEventFactoryInterface* factory,
-        bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
+        bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
+        int32_t* displayId) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld",
             mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime);
@@ -404,6 +407,7 @@
 
     *outSeq = 0;
     *outEvent = NULL;
+    *displayId = -1;  // Invalid display.
 
     // Fetch the next input message.
     // Loop until an event can be returned or no additional events are received.
@@ -418,7 +422,7 @@
             if (result) {
                 // Consume the next batched event unless batches are being held for later.
                 if (consumeBatches || result != WOULD_BLOCK) {
-                    result = consumeBatch(factory, frameTime, outSeq, outEvent);
+                    result = consumeBatch(factory, frameTime, outSeq, outEvent, displayId);
                     if (*outEvent) {
 #if DEBUG_TRANSPORT_ACTIONS
                         ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
@@ -462,7 +466,7 @@
                     // the previous batch right now and defer the new message until later.
                     mMsgDeferred = true;
                     status_t result = consumeSamples(factory,
-                            batch, batch.samples.size(), outSeq, outEvent);
+                            batch, batch.samples.size(), outSeq, outEvent, displayId);
                     mBatches.removeAt(batchIndex);
                     if (result) {
                         return result;
@@ -496,6 +500,7 @@
             initializeMotionEvent(motionEvent, &mMsg);
             *outSeq = mMsg.body.motion.seq;
             *outEvent = motionEvent;
+            *displayId = mMsg.body.motion.displayId;
 #if DEBUG_TRANSPORT_ACTIONS
             ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
                     mChannel->getName().string(), *outSeq);
@@ -513,14 +518,14 @@
 }
 
 status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory,
-        nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
+        nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
     status_t result;
     for (size_t i = mBatches.size(); i > 0; ) {
         i--;
         Batch& batch = mBatches.editItemAt(i);
         if (frameTime < 0) {
             result = consumeSamples(factory, batch, batch.samples.size(),
-                    outSeq, outEvent);
+                    outSeq, outEvent, displayId);
             mBatches.removeAt(i);
             return result;
         }
@@ -534,7 +539,7 @@
             continue;
         }
 
-        result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
+        result = consumeSamples(factory, batch, split + 1, outSeq, outEvent, displayId);
         const InputMessage* next;
         if (batch.samples.isEmpty()) {
             mBatches.removeAt(i);
@@ -552,7 +557,7 @@
 }
 
 status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory,
-        Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) {
+        Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
     MotionEvent* motionEvent = factory->createMotionEvent();
     if (! motionEvent) return NO_MEMORY;
 
@@ -567,6 +572,7 @@
             mSeqChains.push(seqChain);
             addSample(motionEvent, &msg);
         } else {
+            *displayId = msg.body.motion.displayId;
             initializeMotionEvent(motionEvent, &msg);
         }
         chain = msg.body.motion.seq;
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 8e69c9c..a136738 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -89,7 +89,8 @@
 
     uint32_t consumeSeq;
     InputEvent* event;
-    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
+            0);
     ASSERT_EQ(OK, status)
             << "consumer consume should return OK";
 
@@ -132,6 +133,7 @@
     const uint32_t seq = 15;
     const int32_t deviceId = 1;
     const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+    const int32_t displayId = 0;
     const int32_t action = AMOTION_EVENT_ACTION_MOVE;
     const int32_t actionButton = 0;
     const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
@@ -164,7 +166,7 @@
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
     }
 
-    status = mPublisher->publishMotionEvent(seq, deviceId, source, action, actionButton,
+    status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton,
             flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
             downTime, eventTime, pointerCount,
             pointerProperties, pointerCoords);
@@ -173,7 +175,8 @@
 
     uint32_t consumeSeq;
     InputEvent* event;
-    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
+            0);
     ASSERT_EQ(OK, status)
             << "consumer consume should return OK";
 
@@ -256,7 +259,7 @@
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
@@ -272,7 +275,7 @@
         pointerCoords[i].clear();
     }
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 81b9953..d19f3b8 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -38,31 +38,33 @@
   CHECK_OFFSET(InputMessage::Body::Key, eventTime, 8);
   CHECK_OFFSET(InputMessage::Body::Key, deviceId, 16);
   CHECK_OFFSET(InputMessage::Body::Key, source, 20);
-  CHECK_OFFSET(InputMessage::Body::Key, action, 24);
-  CHECK_OFFSET(InputMessage::Body::Key, flags, 28);
-  CHECK_OFFSET(InputMessage::Body::Key, keyCode, 32);
-  CHECK_OFFSET(InputMessage::Body::Key, scanCode, 36);
-  CHECK_OFFSET(InputMessage::Body::Key, metaState, 40);
-  CHECK_OFFSET(InputMessage::Body::Key, repeatCount, 44);
-  CHECK_OFFSET(InputMessage::Body::Key, downTime, 48);
+  CHECK_OFFSET(InputMessage::Body::Key, displayId, 24);
+  CHECK_OFFSET(InputMessage::Body::Key, action, 28);
+  CHECK_OFFSET(InputMessage::Body::Key, flags, 32);
+  CHECK_OFFSET(InputMessage::Body::Key, keyCode, 36);
+  CHECK_OFFSET(InputMessage::Body::Key, scanCode, 40);
+  CHECK_OFFSET(InputMessage::Body::Key, metaState, 44);
+  CHECK_OFFSET(InputMessage::Body::Key, repeatCount, 48);
+  CHECK_OFFSET(InputMessage::Body::Key, downTime, 56);
 
   CHECK_OFFSET(InputMessage::Body::Motion, seq, 0);
   CHECK_OFFSET(InputMessage::Body::Motion, eventTime, 8);
   CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16);
   CHECK_OFFSET(InputMessage::Body::Motion, source, 20);
-  CHECK_OFFSET(InputMessage::Body::Motion, action, 24);
-  CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 28);
-  CHECK_OFFSET(InputMessage::Body::Motion, flags, 32);
-  CHECK_OFFSET(InputMessage::Body::Motion, metaState, 36);
-  CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 40);
-  CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 44);
-  CHECK_OFFSET(InputMessage::Body::Motion, downTime, 48);
-  CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 56);
-  CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 60);
-  CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 64);
-  CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 68);
-  CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 72);
-  CHECK_OFFSET(InputMessage::Body::Motion, pointers, 80);
+  CHECK_OFFSET(InputMessage::Body::Motion, displayId, 24);
+  CHECK_OFFSET(InputMessage::Body::Motion, action, 28);
+  CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 32);
+  CHECK_OFFSET(InputMessage::Body::Motion, flags, 36);
+  CHECK_OFFSET(InputMessage::Body::Motion, metaState, 40);
+  CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 44);
+  CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 48);
+  CHECK_OFFSET(InputMessage::Body::Motion, downTime, 56);
+  CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 64);
+  CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 68);
+  CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 72);
+  CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 76);
+  CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 80);
+  CHECK_OFFSET(InputMessage::Body::Motion, pointers, 88);
 }
 
 } // namespace android
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index 0a537a3..a0e368c 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -38,7 +38,8 @@
         Sensor(*hwSensor, uuid_t(), halVersion) {
 }
 
-Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion) {
+Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion) :
+        Sensor("") {
     mName = hwSensor.name;
     mVendor = hwSensor.vendor;
     mVersion = hwSensor.version;
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index 3860390..bfb9a55 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -613,6 +613,12 @@
 
     std::unique_ptr<BufferConsumer> buffer_consumer =
         BufferConsumer::Import(std::move(buffer_handle_slot.first));
+    if (!buffer_consumer) {
+      ALOGE("ConsumerQueue::ImportBuffers: Failed to import buffer: slot=%zu",
+            buffer_handle_slot.second);
+      last_error = ErrorStatus(EPIPE);
+      continue;
+    }
 
     // Setup ignore state before adding buffer to the queue.
     if (ignore_on_import_) {
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index 04e3d5f..0d6a732 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -194,6 +194,7 @@
            "ApplicationDisplaySurface::GetQueue: surface_id=%d queue_id=%d",
            surface_id(), queue_id);
 
+  std::lock_guard<std::mutex> autolock(lock_);
   auto search = consumer_queues_.find(queue_id);
   if (search != consumer_queues_.end())
     return search->second;
@@ -202,6 +203,7 @@
 }
 
 std::vector<int32_t> ApplicationDisplaySurface::GetQueueIds() const {
+  std::lock_guard<std::mutex> autolock(lock_);
   std::vector<int32_t> queue_ids;
   for (const auto& entry : consumer_queues_)
     queue_ids.push_back(entry.first);
@@ -270,6 +272,7 @@
 }
 
 std::vector<int32_t> DirectDisplaySurface::GetQueueIds() const {
+  std::lock_guard<std::mutex> autolock(lock_);
   std::vector<int32_t> queue_ids;
   if (direct_queue_)
     queue_ids.push_back(direct_queue_->id());
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index 556183a..5cbee57 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -133,6 +133,7 @@
   void OnQueueEvent(const std::shared_ptr<ConsumerQueue>& consumer_queue,
                     int events) override;
 
+  // Accessed by both message dispatch thread and epoll event thread.
   std::unordered_map<int32_t, std::shared_ptr<ConsumerQueue>> consumer_queues_;
 };
 
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 7de8c62..bb28600 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -682,6 +682,11 @@
 #define EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT 0x3362
 #endif /* EGL_EXT_gl_colorspace_display_p3_linear */
 
+#ifndef EGL_EXT_gl_colorspace_scrgb
+#define EGL_EXT_gl_colorspace_scrgb 1
+#define EGL_GL_COLORSPACE_SCRGB_EXT       0x3351
+#endif /* EGL_EXT_gl_colorspace_scrgb */
+
 #ifndef EGL_EXT_gl_colorspace_scrgb_linear
 #define EGL_EXT_gl_colorspace_scrgb_linear 1
 #define EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT 0x3350
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index a344636..b4cc211 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -127,7 +127,14 @@
         "EGL/Loader.cpp",
         "EGL/BlobCache.cpp",
     ],
-    shared_libs: ["libvndksupport"],
+    shared_libs: [
+        "libvndksupport",
+        "android.hardware.configstore@1.0",
+        "android.hardware.configstore-utils",
+        "libhidlbase",
+        "libhidltransport",
+        "libutils",
+    ],
     static_libs: ["libEGL_getProcAddress"],
     ldflags: ["-Wl,--exclude-libs=ALL"],
     export_include_dirs: ["EGL/include"],
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index c5feb89..0214b0e 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -87,9 +87,6 @@
         "EGL_ANDROID_get_native_client_buffer "
         "EGL_ANDROID_front_buffer_auto_refresh "
         "EGL_ANDROID_get_frame_timestamps "
-        "EGL_EXT_gl_colorspace_scrgb_linear "
-        "EGL_EXT_gl_colorspace_display_p3_linear "
-        "EGL_EXT_gl_colorspace_display_p3 "
         ;
 
 char const * const gExtensionString  =
@@ -467,6 +464,8 @@
         return HAL_DATASPACE_DISPLAY_P3;
     } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT) {
         return HAL_DATASPACE_DISPLAY_P3_LINEAR;
+    } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_EXT) {
+        return HAL_DATASPACE_V0_SCRGB;
     } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) {
         return HAL_DATASPACE_V0_SCRGB_LINEAR;
     }
@@ -526,25 +525,34 @@
     return stripped;
 }
 
-static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
-                                         EGLint& colorSpace, android_dataspace& dataSpace) {
+static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, NativeWindowType window,
+                                         const EGLint* attrib_list, EGLint& colorSpace,
+                                         android_dataspace& dataSpace) {
     colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR;
     dataSpace = HAL_DATASPACE_UNKNOWN;
+
     if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
         for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
             if (*attr == EGL_GL_COLORSPACE_KHR) {
                 colorSpace = attr[1];
                 bool found = false;
+                bool verify = true;
                 // Verify that color space is allowed
                 if (colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
                     colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR) {
+                    // SRGB and LINEAR are always supported when EGL_KHR_gl_colorspace
+                    // is available, so no need to verify.
                     found = true;
+                    verify = false;
                 } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_linear &&
                            dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_linear")) {
                     found = true;
                 } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_pq &&
                            dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_pq")) {
                     found = true;
+                } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_EXT &&
+                           dp->haveExtension("EGL_EXT_gl_colorspace_scrgb")) {
+                    found = true;
                 } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT &&
                            dp->haveExtension("EGL_EXT_gl_colorspace_scrgb_linear")) {
                     found = true;
@@ -558,6 +566,31 @@
                 if (!found) {
                     return false;
                 }
+                if (verify && window) {
+                    bool wide_color_support = true;
+                    // Ordinarily we'd put a call to native_window_get_wide_color_support
+                    // at the beginning of the function so that we'll have the
+                    // result when needed elsewhere in the function.
+                    // However, because eglCreateWindowSurface is called by SurfaceFlinger and
+                    // SurfaceFlinger is required to answer the call below we would
+                    // end up in a deadlock situation. By moving the call to only happen
+                    // if the application has specifically asked for wide-color we avoid
+                    // the deadlock with SurfaceFlinger since it will not ask for a
+                    // wide-color surface.
+                    int err = native_window_get_wide_color_support(window, &wide_color_support);
+
+                    if (err) {
+                        ALOGE("getColorSpaceAttribute: invalid window (win=%p) "
+                              "failed (%#x) (already connected to another API?)",
+                              window, err);
+                        return false;
+                    }
+                    if (!wide_color_support) {
+                        // Application has asked for a wide-color colorspace but
+                        // wide-color support isn't available on the display the window is on.
+                        return false;
+                    }
+                }
                 // Only change the dataSpace from default if the application
                 // has explicitly set the color space with a EGL_GL_COLORSPACE_KHR attribute.
                 dataSpace = modifyBufferDataspace(dataSpace, colorSpace);
@@ -567,6 +600,11 @@
     return true;
 }
 
+static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
+                                         EGLint& colorSpace, android_dataspace& dataSpace) {
+    return getColorSpaceAttribute(dp, NULL, attrib_list, colorSpace, dataSpace);
+}
+
 void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, EGLint& format) {
     // Set the native window's buffers format to match what this config requests.
     // Whether to use sRGB gamma is not part of the EGLconfig, but is part
@@ -661,7 +699,7 @@
         // now select correct colorspace and dataspace based on user's attribute list
         EGLint colorSpace;
         android_dataspace dataSpace;
-        if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
+        if (!getColorSpaceAttribute(dp, window, attrib_list, colorSpace, dataSpace)) {
             ALOGE("error invalid colorspace: %d", colorSpace);
             return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
         }
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index b696920..4e5833a 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -30,6 +30,12 @@
 #include "Loader.h"
 #include <cutils/properties.h>
 
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
@@ -192,6 +198,18 @@
         mClientApiString = sClientApiString;
 
         mExtensionString = gBuiltinExtensionString;
+
+        bool wideColorBoardConfig =
+                getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(
+                        false);
+
+        // Add wide-color extensions if device can support wide-color
+        if (wideColorBoardConfig) {
+            mExtensionString.append(
+                    "EGL_EXT_gl_colorspace_scrgb EGL_EXT_gl_colorspace_scrgb_linear "
+                    "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 ");
+        }
+
         char const* start = gExtensionString;
         do {
             // length of the extension name
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 2efb340..69067d2 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -869,10 +869,7 @@
         return true;
     }
 
-    // TODO: support sending secondary display events to input monitors
-    if (isMainDisplay(entry->displayId)) {
-        addMonitoringTargetsLocked(inputTargets);
-    }
+    addMonitoringTargetsLocked(inputTargets);
 
     // Dispatch the motion.
     if (conflictingPointerActions) {
@@ -2026,7 +2023,7 @@
 
             // Publish the motion event.
             status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
-                    motionEntry->deviceId, motionEntry->source,
+                    motionEntry->deviceId, motionEntry->source, motionEntry->displayId,
                     dispatchEntry->resolvedAction, motionEntry->actionButton,
                     dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
                     motionEntry->metaState, motionEntry->buttonState,
@@ -2600,8 +2597,9 @@
         uint32_t policyFlags) {
 #if DEBUG_INBOUND_EVENT_DETAILS
     ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
-            "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x",
-            event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags);
+            "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x, displayId=%d",
+            event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags,
+            displayId);
 #endif
 
     nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 97565aa..cc81a29 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2329,6 +2329,35 @@
         || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
 }
 
+bool KeyboardInputMapper::isMediaKey(int32_t keyCode) {
+    switch (keyCode) {
+    case AKEYCODE_MEDIA_PLAY:
+    case AKEYCODE_MEDIA_PAUSE:
+    case AKEYCODE_MEDIA_PLAY_PAUSE:
+    case AKEYCODE_MUTE:
+    case AKEYCODE_HEADSETHOOK:
+    case AKEYCODE_MEDIA_STOP:
+    case AKEYCODE_MEDIA_NEXT:
+    case AKEYCODE_MEDIA_PREVIOUS:
+    case AKEYCODE_MEDIA_REWIND:
+    case AKEYCODE_MEDIA_RECORD:
+    case AKEYCODE_MEDIA_FAST_FORWARD:
+    case AKEYCODE_MEDIA_SKIP_FORWARD:
+    case AKEYCODE_MEDIA_SKIP_BACKWARD:
+    case AKEYCODE_MEDIA_STEP_FORWARD:
+    case AKEYCODE_MEDIA_STEP_BACKWARD:
+    case AKEYCODE_MEDIA_AUDIO_TRACK:
+    case AKEYCODE_VOLUME_UP:
+    case AKEYCODE_VOLUME_DOWN:
+    case AKEYCODE_VOLUME_MUTE:
+    case AKEYCODE_TV_AUDIO_DESCRIPTION:
+    case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP:
+    case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN:
+        return true;
+    }
+    return false;
+}
+
 void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
         int32_t usageCode) {
     int32_t keyCode;
@@ -2402,7 +2431,7 @@
     // For internal keyboards, the key layout file should specify the policy flags for
     // each wake key individually.
     // TODO: Use the input device configuration to control this behavior more finely.
-    if (down && getDevice()->isExternal()) {
+    if (down && getDevice()->isExternal() && !isMediaKey(keyCode)) {
         policyFlags |= POLICY_FLAG_WAKE;
     }
 
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 157fa4f..c4f786a 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -1128,6 +1128,7 @@
     void dumpParameters(String8& dump);
 
     bool isKeyboardOrGamepadKey(int32_t scanCode);
+    bool isMediaKey(int32_t keyCode);
 
     void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode);
 
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index bd9b8aa..ea04839 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -377,11 +377,16 @@
 DispSync::DispSync(const char* name) :
         mName(name),
         mRefreshSkipCount(0),
-        mThread(new DispSyncThread(name)),
-        mIgnorePresentFences(!SurfaceFlinger::hasSyncFramework){
+        mThread(new DispSyncThread(name)) {
+}
 
-    mPresentTimeOffset = SurfaceFlinger::dispSyncPresentTimeOffset;
+DispSync::~DispSync() {}
+
+void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) {
+    mIgnorePresentFences = !hasSyncFramework;
+    mPresentTimeOffset = dispSyncPresentTimeOffset;
     mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
+
     // set DispSync to SCHED_FIFO to minimize jitter
     struct sched_param param = {0};
     param.sched_priority = 2;
@@ -389,7 +394,6 @@
         ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
     }
 
-
     reset();
     beginResync();
 
@@ -405,8 +409,6 @@
     }
 }
 
-DispSync::~DispSync() {}
-
 void DispSync::reset() {
     Mutex::Autolock lock(mMutex);
 
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 82ae795..3c34fb0 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -55,6 +55,8 @@
     explicit DispSync(const char* name);
     ~DispSync();
 
+    void init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset);
+
     // reset clears the resync samples and error value.
     void reset();
 
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a0abf12..fc60002 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -442,6 +442,11 @@
 android_color_mode_t DisplayDevice::getActiveColorMode() const {
     return mActiveColorMode;
 }
+
+void DisplayDevice::setCompositionDataSpace(android_dataspace dataspace) {
+    ANativeWindow* const window = mNativeWindow.get();
+    native_window_set_buffers_data_space(window, dataspace);
+}
 #endif
 
 // ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e2852a7..8636e2a 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -141,6 +141,7 @@
 
     uint32_t                getLayerStack() const { return mLayerStack; }
     int32_t                 getDisplayType() const { return mType; }
+    bool                    isPrimary() const { return mType == DISPLAY_PRIMARY; }
     int32_t                 getHwcDisplayId() const { return mHwcDisplayId; }
     const wp<IBinder>&      getDisplayToken() const { return mDisplayToken; }
 
@@ -189,6 +190,7 @@
 #ifdef USE_HWC2
     android_color_mode_t getActiveColorMode() const;
     void setActiveColorMode(android_color_mode_t mode);
+    void setCompositionDataSpace(android_dataspace dataspace);
 #endif
 
     /* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 5b869e1..68d7a18 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -106,12 +106,6 @@
     if (result != NO_ERROR) {
         ALOGE("error latching next FramebufferSurface buffer: %s (%d)",
                 strerror(-result), result);
-        return result;
-    }
-    result = mHwc.setClientTarget(mDisplayType, slot,
-            acquireFence, buf, dataspace);
-    if (result != NO_ERROR) {
-        ALOGE("error posting framebuffer: %d", result);
     }
     return result;
 #else
@@ -182,7 +176,13 @@
 #else
     outBuffer = mCurrentBuffer;
 #endif
-    return NO_ERROR;
+    status_t result =
+            mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace);
+    if (result != NO_ERROR) {
+        ALOGE("error posting framebuffer: %d", result);
+    }
+
+    return result;
 }
 
 #ifndef USE_HWC2
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 392479f..2306d1a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -166,6 +166,8 @@
 
     virtual ~Layer();
 
+    void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; }
+
     // the this layer's size and format
     status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
 
@@ -249,6 +251,10 @@
     uint32_t getTransactionFlags(uint32_t flags);
     uint32_t setTransactionFlags(uint32_t flags);
 
+    bool belongsToDisplay(uint32_t layerStack, bool isPrimaryDisplay) const {
+        return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay);
+    }
+
     void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh,
             bool useIdentityTransform) const;
     Rect computeBounds(const Region& activeTransparentRegion) const;
@@ -701,6 +707,8 @@
     String8 mTransactionName; // A cached version of "TX - " + mName for systraces
     PixelFormat mFormat;
 
+    bool mPrimaryDisplayOnly = false;
+
     // these are protected by an external lock
     State mCurrentState;
     State mDrawingState;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 63f260a..0f6c581 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -195,6 +195,8 @@
     hasWideColorDisplay =
             getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
 
+    mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset);
+
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
 
@@ -383,6 +385,7 @@
 #ifdef USE_HWC2
         sp<DisplayDevice> hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]));
         if (hw->getWideColorSupport()) {
+            hw->setCompositionDataSpace(HAL_DATASPACE_V0_SRGB);
             setActiveColorModeInternal(hw, HAL_COLOR_MODE_SRGB);
         }
 #endif
@@ -1222,6 +1225,7 @@
                                              hasWideColorModes && hasWideColorDisplay);
     mDisplays.add(token, hw);
     setActiveColorModeInternal(hw, HAL_COLOR_MODE_NATIVE);
+    hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN);
 }
 
 void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) {
@@ -1680,12 +1684,11 @@
             const Transform& tr(displayDevice->getTransform());
             const Rect bounds(displayDevice->getBounds());
             if (displayDevice->isDisplayOn()) {
-                computeVisibleRegions(
-                        displayDevice->getLayerStack(), dirtyRegion,
-                        opaqueRegion);
+                computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
 
                 mDrawingState.traverseInZOrder([&](Layer* layer) {
-                    if (layer->getLayerStack() == displayDevice->getLayerStack()) {
+                    if (layer->belongsToDisplay(displayDevice->getLayerStack(),
+                                displayDevice->isPrimary())) {
                         Region drawRegion(tr.transform(
                                 layer->visibleNonTransparentRegion));
                         drawRegion.andSelf(bounds);
@@ -1871,6 +1874,7 @@
             // To achieve this we suppress color mode changes until after the boot animation
             if (mBootFinished) {
                 setActiveColorModeInternal(displayDevice, newColorMode);
+                displayDevice->setCompositionDataSpace(newDataSpace);
             }
         }
     }
@@ -2206,7 +2210,7 @@
                 disp.clear();
                 for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
                     sp<const DisplayDevice> hw(mDisplays[dpy]);
-                    if (hw->getLayerStack() == currentlayerStack) {
+                    if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
                         if (disp == NULL) {
                             disp = hw;
                         } else {
@@ -2255,7 +2259,7 @@
                 // TODO: we could cache the transformed region
                 Region visibleReg;
                 visibleReg.set(layer->computeScreenBounds());
-                invalidateLayerStack(layer->getLayerStack(), visibleReg);
+                invalidateLayerStack(layer, visibleReg);
             }
         });
     }
@@ -2304,7 +2308,7 @@
     mTransactionCV.broadcast();
 }
 
-void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack,
+void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
         Region& outDirtyRegion, Region& outOpaqueRegion)
 {
     ATRACE_CALL();
@@ -2321,7 +2325,7 @@
         const Layer::State& s(layer->getDrawingState());
 
         // only consider the layers on the given layer stack
-        if (layer->getLayerStack() != layerStack)
+        if (!layer->belongsToDisplay(displayDevice->getLayerStack(), displayDevice->isPrimary()))
             return;
 
         /*
@@ -2436,11 +2440,10 @@
     outOpaqueRegion = aboveOpaqueLayers;
 }
 
-void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
-        const Region& dirty) {
+void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
     for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
         const sp<DisplayDevice>& hw(mDisplays[dpy]);
-        if (hw->getLayerStack() == layerStack) {
+        if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
             hw->dirtyRegion.orSelf(dirty);
         }
     }
@@ -2481,7 +2484,7 @@
     for (auto& layer : mLayersWithQueuedFrames) {
         const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
         layer->useSurfaceDamage();
-        invalidateLayerStack(layer->getLayerStack(), dirty);
+        invalidateLayerStack(layer, dirty);
         if (layer->isBufferLatched()) {
             newDataLatched = true;
         }
@@ -3103,6 +3106,13 @@
         return result;
     }
 
+    // window type is WINDOW_TYPE_DONT_SCREENSHOT from SurfaceControl.java
+    // TODO b/64227542
+    if (windowType == 441731) {
+        windowType = 2024; // TYPE_NAVIGATION_BAR_PANEL
+        layer->setPrimaryDisplayOnly();
+    }
+
     layer->setInfo(windowType, ownerUid);
 
     result = addClientLayer(client, *handle, *gbp, layer, *parent);
@@ -4330,7 +4340,7 @@
     // We loop through the first level of layers without traversing,
     // as we need to interpret min/max layer Z in the top level Z space.
     for (const auto& layer : mDrawingState.layersSortedByZ) {
-        if (layer->getLayerStack() != hw->getLayerStack()) {
+        if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
             continue;
         }
         const Layer::State& state(layer->getDrawingState());
@@ -4382,7 +4392,7 @@
     bool secureLayerIsVisible = false;
     for (const auto& layer : mDrawingState.layersSortedByZ) {
         const Layer::State& state(layer->getDrawingState());
-        if ((layer->getLayerStack() != hw->getLayerStack()) ||
+        if (layer->belongsToDisplay(hw->getLayerStack(), false) ||
                 (state.z < minLayerZ || state.z > maxLayerZ)) {
             continue;
         }
@@ -4493,7 +4503,7 @@
         size_t i = 0;
         for (const auto& layer : mDrawingState.layersSortedByZ) {
             const Layer::State& state(layer->getDrawingState());
-            if (layer->getLayerStack() == hw->getLayerStack() && state.z >= minLayerZ &&
+            if (layer->belongsToDisplay(hw->getLayerStack(), false) && state.z >= minLayerZ &&
                     state.z <= maxLayerZ) {
                 layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
                     ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 48bbd13..acfad46 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -494,7 +494,7 @@
 
     // mark a region of a layer stack dirty. this updates the dirty
     // region of all screens presenting this layer stack.
-    void invalidateLayerStack(uint32_t layerStack, const Region& dirty);
+    void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
 
 #ifndef USE_HWC2
     int32_t allocateHwcDisplayId(DisplayDevice::DisplayType type);
@@ -510,7 +510,7 @@
      * Compositing
      */
     void invalidateHwcGeometry();
-    void computeVisibleRegions(uint32_t layerStack,
+    void computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
             Region& dirtyRegion, Region& opaqueRegion);
 
     void preComposition(nsecs_t refreshStartTime);
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 2b56928..247d80b 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -1361,8 +1361,7 @@
             const Transform& tr(hw->getTransform());
             const Rect bounds(hw->getBounds());
             if (hw->isDisplayOn()) {
-                computeVisibleRegions(hw->getLayerStack(), dirtyRegion,
-                        opaqueRegion);
+                computeVisibleRegions(hw, dirtyRegion, opaqueRegion);
 
                 mDrawingState.traverseInZOrder([&](Layer* layer) {
                     if (layer->getLayerStack() == hw->getLayerStack()) {
@@ -1863,7 +1862,7 @@
                 // TODO: we could cache the transformed region
                 Region visibleReg;
                 visibleReg.set(layer->computeScreenBounds());
-                invalidateLayerStack(layer->getLayerStack(), visibleReg);
+                invalidateLayerStack(layer, visibleReg);
             }
         });
     }
@@ -1924,7 +1923,7 @@
     mTransactionCV.broadcast();
 }
 
-void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack,
+void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
         Region& outDirtyRegion, Region& outOpaqueRegion)
 {
     ATRACE_CALL();
@@ -1940,7 +1939,7 @@
         const Layer::State& s(layer->getDrawingState());
 
         // only consider the layers on the given layer stack
-        if (layer->getLayerStack() != layerStack)
+        if (layer->getLayerStack() != displayDevice->getLayerStack())
             return;
 
         /*
@@ -2055,8 +2054,8 @@
     outOpaqueRegion = aboveOpaqueLayers;
 }
 
-void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
-        const Region& dirty) {
+void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
+    uint32_t layerStack = layer->getLayerStack();
     for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
         const sp<DisplayDevice>& hw(mDisplays[dpy]);
         if (hw->getLayerStack() == layerStack) {
@@ -2099,7 +2098,7 @@
         Layer* layer = layersWithQueuedFrames[i];
         const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
         layer->useSurfaceDamage();
-        invalidateLayerStack(layer->getLayerStack(), dirty);
+        invalidateLayerStack(layer, dirty);
     }
 
     mVisibleRegionsDirty |= visibleRegions;
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index 251ed0e..bcfdad3 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -94,9 +94,6 @@
   if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
     return EINVAL;
   }
-  if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
-    return EINVAL;
-  }
   int32_t device_x = x * kWidth;
   int32_t device_y = y * kHeight;
   Touchpad& touchpad = touchpad_[touchpad_id];
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 3efc131..11161c6 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -1255,6 +1255,7 @@
     VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT                      = 1000104011,
     VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT                   = 1000104012,
     VK_COLOR_SPACE_PASS_THROUGH_EXT                         = 1000104013,
+    VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT              = 1000104014,
 }
 
 @extension("VK_EXT_debug_report") // 12
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index ee30913..f0209d6 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -3355,6 +3355,7 @@
     VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
     VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
     VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
+    VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014,
     VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1),
@@ -5829,7 +5830,7 @@
 #endif
 
 #define VK_EXT_swapchain_colorspace 1
-#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 2
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 3
 #define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
 
 
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index ded9549..069fb36 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -640,6 +640,8 @@
     const VkSurfaceFormatKHR kWideColorFormats[] = {
         {VK_FORMAT_R16G16B16A16_SFLOAT,
          VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
+        {VK_FORMAT_R16G16B16A16_SFLOAT,
+         VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT},
         {VK_FORMAT_A2R10G10B10_UNORM_PACK32,
          VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
     };
@@ -1093,12 +1095,9 @@
         image_native_buffer.stride = img.buffer->stride;
         image_native_buffer.format = img.buffer->format;
         image_native_buffer.usage = int(img.buffer->usage);
-        // TODO: Adjust once ANativeWindowBuffer supports gralloc1-style usage.
-        // For now, this is the same translation Gralloc1On0Adapter does.
-        image_native_buffer.usage2.consumer =
-            static_cast<uint64_t>(img.buffer->usage);
-        image_native_buffer.usage2.producer =
-            static_cast<uint64_t>(img.buffer->usage);
+        android_convertGralloc0To1Usage(int(img.buffer->usage),
+            &image_native_buffer.usage2.producer,
+            &image_native_buffer.usage2.consumer);
 
         result =
             dispatch.CreateImage(device, &image_create, nullptr, &img.image);