Merge "SF: VSyncReactor change offsets at correct time"
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 08a31c1..402767a 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -15,6 +15,7 @@
 cc_defaults {
     name: "idlcli-defaults",
     shared_libs: [
+        "android.hardware.vibrator-ndk_platform",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
@@ -24,7 +25,6 @@
         "libhidlbase",
         "liblog",
         "libutils",
-        "vintf-vibrator-ndk_platform",
     ],
     cflags: [
         "-DLOG_TAG=\"idlcli\"",
diff --git a/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-11-ratio.png b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-11-ratio.png
new file mode 100644
index 0000000..b6c0765
--- /dev/null
+++ b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-11-ratio.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-169-ratio.png b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-169-ratio.png
new file mode 100644
index 0000000..4e975e5
--- /dev/null
+++ b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-169-ratio.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-ratio.png b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-ratio.png
new file mode 100644
index 0000000..a331095
--- /dev/null
+++ b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-ratio.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-square-ratio.png b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-square-ratio.png
new file mode 100644
index 0000000..41e6668
--- /dev/null
+++ b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-square-ratio.png
Binary files differ
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index 6479109..a9c2311 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -178,6 +178,10 @@
 
           this->callbacks_.key_authorized(arg, id);
           this->dispatched_prompt_ = std::nullopt;
+
+          // We need to dispatch pending prompts here upon success as well,
+          // since we might have multiple queued prompts.
+          DispatchPendingPrompt();
         } else if (packet[0] == 'N' && packet[1] == 'O') {
           CHECK_EQ(2UL, packet.length());
           // TODO: Do we want a callback if the key is denied?
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 54f383e..208d729 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -36,7 +36,10 @@
 DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
                                                ISurfaceComposer::VsyncSource vsyncSource,
                                                ISurfaceComposer::ConfigChanged configChanged)
-      : mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) {
+      : mLooper(looper),
+        mReceiver(vsyncSource, configChanged),
+        mWaitingForVsync(false),
+        mConfigChangeFlag(configChanged) {
     ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
 }
 
@@ -86,6 +89,18 @@
     return OK;
 }
 
+void DisplayEventDispatcher::toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) {
+    if (mConfigChangeFlag == configChangeFlag) {
+        return;
+    }
+    status_t status = mReceiver.toggleConfigEvents(configChangeFlag);
+    if (status) {
+        ALOGW("Failed enable config events, status=%d", status);
+        return;
+    }
+    mConfigChangeFlag = configChangeFlag;
+}
+
 int DisplayEventDispatcher::handleEvent(int, int events, void*) {
     if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
         ALOGE("Display event receiver pipe was closed or an error occurred.  "
@@ -140,7 +155,7 @@
                     break;
                 case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
                     dispatchConfigChanged(ev.header.timestamp, ev.header.displayId,
-                                          ev.config.configId);
+                                          ev.config.configId, ev.config.vsyncPeriod);
                     break;
                 default:
                     ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index b8faa2d..fd6aaf8 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -79,6 +79,14 @@
     return NO_INIT;
 }
 
+status_t DisplayEventReceiver::toggleConfigEvents(
+        ISurfaceComposer::ConfigChanged configChangeFlag) {
+    if (mEventConnection != nullptr) {
+        mEventConnection->toggleConfigEvents(configChangeFlag);
+        return NO_ERROR;
+    }
+    return NO_INIT;
+}
 
 ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
         size_t count) {
diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp
index c0e246f..dda5acf 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -26,7 +26,8 @@
     STEAL_RECEIVE_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
     SET_VSYNC_RATE,
     REQUEST_NEXT_VSYNC,
-    LAST = REQUEST_NEXT_VSYNC,
+    TOGGLE_CONFIG_EVENTS,
+    LAST = TOGGLE_CONFIG_EVENTS,
 };
 
 } // Anonymous namespace
@@ -53,6 +54,12 @@
         callRemoteAsync<decltype(&IDisplayEventConnection::requestNextVsync)>(
                 Tag::REQUEST_NEXT_VSYNC);
     }
+
+    void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) override {
+        callRemoteAsync<decltype(
+                &IDisplayEventConnection::toggleConfigEvents)>(Tag::TOGGLE_CONFIG_EVENTS,
+                                                               configChangeFlag);
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this translation unit (see
@@ -74,6 +81,8 @@
             return callLocal(data, reply, &IDisplayEventConnection::setVsyncRate);
         case Tag::REQUEST_NEXT_VSYNC:
             return callLocalAsync(data, reply, &IDisplayEventConnection::requestNextVsync);
+        case Tag::TOGGLE_CONFIG_EVENTS:
+            return callLocalAsync(data, reply, &IDisplayEventConnection::toggleConfigEvents);
     }
 }
 
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 1d887ea..f378fc5 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -484,14 +484,22 @@
         mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator(
                                                                 callbackIds.begin()),
                                                         std::make_move_iterator(callbackIds.end()));
-        // register surface controls for this listener that is merging
-        for (const auto& surfaceControl : surfaceControls) {
-            registerSurfaceControlForCallback(surfaceControl);
-        }
 
-        mListenerCallbacks[listener]
-                .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()),
-                                        std::make_move_iterator(surfaceControls.end()));
+        mListenerCallbacks[listener].surfaceControls.insert(surfaceControls.begin(),
+                                                            surfaceControls.end());
+
+        auto& currentProcessCallbackInfo =
+                mListenerCallbacks[TransactionCompletedListener::getIInstance()];
+        currentProcessCallbackInfo.surfaceControls
+                .insert(std::make_move_iterator(surfaceControls.begin()),
+                        std::make_move_iterator(surfaceControls.end()));
+
+        // register all surface controls for all callbackIds for this listener that is merging
+        for (const auto& surfaceControl : currentProcessCallbackInfo.surfaceControls) {
+            TransactionCompletedListener::getInstance()
+                    ->addSurfaceControlToCallbacks(surfaceControl,
+                                                   currentProcessCallbackInfo.callbackIds);
+        }
     }
 
     mInputWindowCommands.merge(other.mInputWindowCommands);
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index f0b7ff5..0b71801 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -31,6 +31,7 @@
     status_t initialize();
     void dispose();
     status_t scheduleVsync();
+    void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag);
 
 protected:
     virtual ~DisplayEventDispatcher() = default;
@@ -39,12 +40,13 @@
     sp<Looper> mLooper;
     DisplayEventReceiver mReceiver;
     bool mWaitingForVsync;
+    ISurfaceComposer::ConfigChanged mConfigChangeFlag;
 
     virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0;
     virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
                                  bool connected) = 0;
     virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
-                                       int32_t configId) = 0;
+                                       int32_t configId, nsecs_t vsyncPeriod) = 0;
 
     virtual int handleEvent(int receiveFd, int events, void* data);
     bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index a558cf9..109e28b 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -73,6 +73,7 @@
 
         struct Config {
             int32_t configId;
+            nsecs_t vsyncPeriod;
         };
 
         Header header;
@@ -144,6 +145,11 @@
      */
     status_t requestNextVsync();
 
+    /*
+     * toggleConfigEvents() toggles delivery of config change events.
+     */
+    status_t toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag);
+
 private:
     sp<IDisplayEventConnection> mEventConnection;
     std::unique_ptr<gui::BitTube> mDataChannel;
diff --git a/libs/gui/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h
index d783f74..8b35ef6 100644
--- a/libs/gui/include/gui/IDisplayEventConnection.h
+++ b/libs/gui/include/gui/IDisplayEventConnection.h
@@ -18,7 +18,7 @@
 
 #include <binder/IInterface.h>
 #include <binder/SafeInterface.h>
-
+#include <gui/ISurfaceComposer.h>
 #include <utils/Errors.h>
 
 #include <cstdint>
@@ -51,6 +51,13 @@
      * requestNextVsync() schedules the next vsync event. It has no effect if the vsync rate is > 0.
      */
     virtual void requestNextVsync() = 0; // Asynchronous
+
+    /*
+     * togglesConfigEvents() configures whether or not display config changes
+     * should be propagated.
+     */
+    virtual void toggleConfigEvents(
+            ISurfaceComposer::ConfigChanged configChangeFlag) = 0; // Asynchronous
 };
 
 class BnDisplayEventConnection : public SafeBnInterface<IDisplayEventConnection> {
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 05ff93e..7e71ede 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -17,11 +17,7 @@
 #define LOG_TAG "Choreographer"
 //#define LOG_NDEBUG 0
 
-#include <cinttypes>
-#include <queue>
-#include <thread>
-
-#include <android/choreographer.h>
+#include <apex/choreographer.h>
 #include <gui/DisplayEventDispatcher.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
@@ -29,6 +25,11 @@
 #include <utils/Mutex.h>
 #include <utils/Timers.h>
 
+#include <cinttypes>
+#include <optional>
+#include <queue>
+#include <thread>
+
 namespace android {
 
 static inline const char* toString(bool value) {
@@ -48,11 +49,17 @@
     }
 };
 
+struct RefreshRateCallback {
+    AChoreographer_refreshRateCallback callback;
+    void* data;
+};
 
 class Choreographer : public DisplayEventDispatcher, public MessageHandler {
 public:
     void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
                                   AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
+    void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
+    void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb);
 
     enum {
         MSG_SCHEDULE_CALLBACKS = 0,
@@ -71,18 +78,23 @@
 
     void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
     void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
-    void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
-                               int32_t configId) override;
+    void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId,
+                               nsecs_t vsyncPeriod) override;
 
     void scheduleCallbacks();
 
     // Protected by mLock
-    std::priority_queue<FrameCallback> mCallbacks;
+    std::priority_queue<FrameCallback> mFrameCallbacks;
+
+    // Protected by mLock
+    std::vector<RefreshRateCallback> mRefreshRateCallbacks;
+    nsecs_t mVsyncPeriod = 0;
 
     mutable Mutex mLock;
 
     const sp<Looper> mLooper;
     const std::thread::id mThreadId;
+    const std::optional<PhysicalDisplayId> mInternalDisplayId;
 };
 
 
@@ -104,9 +116,11 @@
     return gChoreographer;
 }
 
-Choreographer::Choreographer(const sp<Looper>& looper) :
-    DisplayEventDispatcher(looper), mLooper(looper), mThreadId(std::this_thread::get_id()) {
-}
+Choreographer::Choreographer(const sp<Looper>& looper)
+      : DisplayEventDispatcher(looper),
+        mLooper(looper),
+        mThreadId(std::this_thread::get_id()),
+        mInternalDisplayId(SurfaceComposerClient::getInternalDisplayId()) {}
 
 void Choreographer::postFrameCallbackDelayed(
         AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) {
@@ -114,7 +128,7 @@
     FrameCallback callback{cb, cb64, data, now + delay};
     {
         AutoMutex _l{mLock};
-        mCallbacks.push(callback);
+        mFrameCallbacks.push(callback);
     }
     if (callback.dueTime <= now) {
         if (std::this_thread::get_id() != mThreadId) {
@@ -129,10 +143,31 @@
     }
 }
 
+void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) {
+    {
+        AutoMutex _l{mLock};
+        mRefreshRateCallbacks.emplace_back(RefreshRateCallback{cb, data});
+        toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedDispatch);
+    }
+}
+
+void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb) {
+    {
+        AutoMutex _l{mLock};
+        std::remove_if(mRefreshRateCallbacks.begin(), mRefreshRateCallbacks.end(),
+                       [&](const RefreshRateCallback& callback) {
+                           return cb == callback.callback;
+                       });
+        if (mRefreshRateCallbacks.empty()) {
+            toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedSuppress);
+        }
+    }
+}
+
 void Choreographer::scheduleCallbacks() {
     AutoMutex _{mLock};
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    if (mCallbacks.top().dueTime <= now) {
+    if (mFrameCallbacks.top().dueTime <= now) {
         ALOGV("choreographer %p ~ scheduling vsync", this);
         scheduleVsync();
         return;
@@ -147,9 +182,9 @@
     {
         AutoMutex _l{mLock};
         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-        while (!mCallbacks.empty() && mCallbacks.top().dueTime < now) {
-            callbacks.push_back(mCallbacks.top());
-            mCallbacks.pop();
+        while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) {
+            callbacks.push_back(mFrameCallbacks.top());
+            mFrameCallbacks.pop();
         }
     }
     for (const auto& cb : callbacks) {
@@ -167,11 +202,25 @@
             this, displayId, toString(connected));
 }
 
-void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId,
-                                          int32_t configId) {
-    ALOGV("choreographer %p ~ received config changed event (displayId=%"
-            ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%s), ignoring.",
-            this, displayId, toString(configId));
+// TODO(b/74619554): The PhysicalDisplayId is ignored because currently
+// Choreographer only supports dispatching VSYNC events for the internal
+// display, so as such Choreographer does not support the notion of multiple
+// displays. When multi-display choreographer is properly supported, then
+// PhysicalDisplayId should no longer be ignored.
+void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId, int32_t,
+                                          nsecs_t vsyncPeriod) {
+    {
+        AutoMutex _l{mLock};
+        for (const auto& cb : mRefreshRateCallbacks) {
+            // Only perform the callback when the old refresh rate is different
+            // from the new refresh rate, so that we don't dispatch the callback
+            // on every single configuration change.
+            if (mVsyncPeriod != vsyncPeriod) {
+                cb.callback(vsyncPeriod, cb.data);
+                mVsyncPeriod = vsyncPeriod;
+            }
+        }
+    }
 }
 
 void Choreographer::handleMessage(const Message& message) {
@@ -223,3 +272,12 @@
     AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
             nullptr, callback, data, ms2ns(delayMillis));
 }
+void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
+                                                AChoreographer_refreshRateCallback callback,
+                                                void* data) {
+    AChoreographer_to_Choreographer(choreographer)->registerRefreshRateCallback(callback, data);
+}
+void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
+                                                  AChoreographer_refreshRateCallback callback) {
+    AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback);
+}
diff --git a/libs/nativedisplay/include/apex/choreographer.h b/libs/nativedisplay/include/apex/choreographer.h
new file mode 100644
index 0000000..352213e
--- /dev/null
+++ b/libs/nativedisplay/include/apex/choreographer.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/choreographer.h>
+#include <inttypes.h>
+
+__BEGIN_DECLS
+
+/**
+ * Prototype of the function that is called when the display refresh rate
+ * changes. It's passed the new vsync period in nanoseconds, as well as the data
+ * pointer provided by the application that registered a callback.
+ */
+typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, void* data);
+
+/**
+ * Registers a callback to be run when the display refresh rate changes.
+ */
+void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
+                                                AChoreographer_refreshRateCallback, void* data);
+
+/**
+ * Unregisters a callback to be run when the display refresh rate changes.
+ */
+void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
+                                                  AChoreographer_refreshRateCallback);
+
+__END_DECLS
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 3b29c18..3b6a241 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -5,6 +5,8 @@
     AChoreographer_postFrameCallbackDelayed; # apex # introduced=30
     AChoreographer_postFrameCallback64; # apex # introduced=30
     AChoreographer_postFrameCallbackDelayed64; # apex # introduced=30
+    AChoreographer_registerRefreshRateCallback; # apex # introduced=30
+    AChoreographer_unregisterRefreshRateCallback; # apex # introduced=30
   local:
     *;
 };
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c7eb9c3..6fd1629 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1930,6 +1930,11 @@
                                        [&]() { return layerInfo->mutable_visible_region(); });
         LayerProtoHelper::writeToProto(surfaceDamageRegion,
                                        [&]() { return layerInfo->mutable_damage_region(); });
+
+        if (hasColorTransform()) {
+            LayerProtoHelper::writeToProto(getColorTransform(),
+                                           layerInfo->mutable_color_transform());
+        }
     }
 
     if (traceFlags & SurfaceTracing::TRACE_EXTRA) {
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index c94e439..b402270 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -155,5 +155,13 @@
     }
 }
 
+void LayerProtoHelper::writeToProto(const mat4 matrix, ColorTransformProto* colorTransformProto) {
+    for (int i = 0; i < mat4::ROW_SIZE; i++) {
+        for (int j = 0; j < mat4::COL_SIZE; j++) {
+            colorTransformProto->add_val(matrix[i][j]);
+        }
+    }
+}
+
 } // namespace surfaceflinger
 } // namespace android
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 1754a3f..502238d 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -43,6 +43,7 @@
     static void writeToProto(const InputWindowInfo& inputInfo,
                              const wp<Layer>& touchableRegionBounds,
                              std::function<InputWindowInfoProto*()> getInputWindowInfoProto);
+    static void writeToProto(const mat4 matrix, ColorTransformProto* colorTransformProto);
 };
 
 } // namespace surfaceflinger
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index ff800c3..5bdef58 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -103,10 +103,11 @@
 }
 
 DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId,
-                                              HwcConfigIndexType configId) {
+                                              HwcConfigIndexType configId, nsecs_t vsyncPeriod) {
     DisplayEventReceiver::Event event;
     event.header = {DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, displayId, systemTime()};
     event.config.configId = configId.value();
+    event.config.vsyncPeriod = vsyncPeriod;
     return event;
 }
 
@@ -116,7 +117,7 @@
                                              ResyncCallback resyncCallback,
                                              ISurfaceComposer::ConfigChanged configChanged)
       : resyncCallback(std::move(resyncCallback)),
-        configChanged(configChanged),
+        mConfigChanged(configChanged),
         mEventThread(eventThread),
         mChannel(gui::BitTube::DefaultSize) {}
 
@@ -145,6 +146,18 @@
     mEventThread->requestNextVsync(this);
 }
 
+void EventThreadConnection::toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) {
+    ATRACE_NAME("enableConfigEvents");
+    mConfigChanged = configChangeFlag;
+
+    // In principle it's possible for rapidly toggling config events to drop an
+    // event here, but it's unlikely in practice.
+    if (configChangeFlag == ISurfaceComposer::eConfigChangedDispatch) {
+        mForcedConfigChangeDispatch = true;
+        mEventThread->requestLatestConfig();
+    }
+}
+
 status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
     ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
     return size < 0 ? status_t(size) : status_t(NO_ERROR);
@@ -257,6 +270,24 @@
     }
 }
 
+void EventThread::requestLatestConfig() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    auto pendingConfigChange =
+            std::find_if(std::begin(mPendingEvents), std::end(mPendingEvents),
+                         [&](const DisplayEventReceiver::Event& event) {
+                             return event.header.type ==
+                                     DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED;
+                         });
+
+    // If we didn't find a pending config change event, then push out the
+    // latest one we've ever seen.
+    if (pendingConfigChange == std::end(mPendingEvents)) {
+        mPendingEvents.push_back(mLastConfigChangeEvent);
+    }
+
+    mCondition.notify_all();
+}
+
 void EventThread::onScreenReleased() {
     std::lock_guard<std::mutex> lock(mMutex);
     if (!mVSyncState || mVSyncState->synthetic) {
@@ -292,10 +323,11 @@
     mCondition.notify_all();
 }
 
-void EventThread::onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) {
+void EventThread::onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId,
+                                  nsecs_t vsyncPeriod) {
     std::lock_guard<std::mutex> lock(mMutex);
 
-    mPendingEvents.push_back(makeConfigChanged(displayId, configId));
+    mPendingEvents.push_back(makeConfigChanged(displayId, configId, vsyncPeriod));
     mCondition.notify_all();
 }
 
@@ -325,6 +357,9 @@
                         mInterceptVSyncsCallback(event->header.timestamp);
                     }
                     break;
+                case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
+                    mLastConfigChangeEvent = *event;
+                    break;
             }
         }
 
@@ -398,8 +433,11 @@
         case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
             return true;
 
-        case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
-            return connection->configChanged == ISurfaceComposer::eConfigChangedDispatch;
+        case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: {
+            const bool forcedDispatch = connection->mForcedConfigChangeDispatch.exchange(false);
+            return forcedDispatch ||
+                    connection->mConfigChanged == ISurfaceComposer::eConfigChangedDispatch;
+        }
 
         case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
             switch (connection->vsyncRequest) {
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index a42546c..641b2a5 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -81,12 +81,19 @@
     status_t stealReceiveChannel(gui::BitTube* outChannel) override;
     status_t setVsyncRate(uint32_t rate) override;
     void requestNextVsync() override; // asynchronous
+    void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) override;
 
     // Called in response to requestNextVsync.
     const ResyncCallback resyncCallback;
 
     VSyncRequest vsyncRequest = VSyncRequest::None;
-    const ISurfaceComposer::ConfigChanged configChanged;
+    std::atomic<ISurfaceComposer::ConfigChanged> mConfigChanged =
+            ISurfaceComposer::ConfigChanged::eConfigChangedSuppress;
+    // Store whether we need to force dispatching a config change separately -
+    // if mConfigChanged ever changes before the config change is dispatched
+    // then we still need to propagate an initial config to the app if we
+    // haven't already.
+    std::atomic<bool> mForcedConfigChangeDispatch = false;
 
 private:
     virtual void onFirstRef();
@@ -110,7 +117,8 @@
     virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
 
     // called when SF changes the active config and apps needs to be notified about the change
-    virtual void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) = 0;
+    virtual void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId,
+                                 nsecs_t vsyncPeriod) = 0;
 
     virtual void dump(std::string& result) const = 0;
 
@@ -121,6 +129,11 @@
     virtual void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) = 0;
     // Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
     virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
+
+    // Dispatches the most recent configuration
+    // Usage of this method assumes that only the primary internal display
+    // supports multiple display configurations.
+    virtual void requestLatestConfig() = 0;
 };
 
 namespace impl {
@@ -138,6 +151,7 @@
     status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
     void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
     void requestNextVsync(const sp<EventThreadConnection>& connection) override;
+    void requestLatestConfig() override;
 
     // called before the screen is turned off from main thread
     void onScreenReleased() override;
@@ -147,7 +161,8 @@
 
     void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
 
-    void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) override;
+    void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId,
+                         nsecs_t vsyncPeriod) override;
 
     void dump(std::string& result) const override;
 
@@ -182,6 +197,7 @@
 
     std::vector<wp<EventThreadConnection>> mDisplayEventConnections GUARDED_BY(mMutex);
     std::deque<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
+    DisplayEventReceiver::Event mLastConfigChangeEvent GUARDED_BY(mMutex);
 
     // VSYNC state of connected display.
     struct VSyncState {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index e845e8c..ff9cf86 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -222,9 +222,9 @@
 }
 
 void Scheduler::onConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
-                                HwcConfigIndexType configId) {
+                                HwcConfigIndexType configId, nsecs_t vsyncPeriod) {
     RETURN_IF_INVALID_HANDLE(handle);
-    mConnections[handle].thread->onConfigChanged(displayId, configId);
+    mConnections[handle].thread->onConfigChanged(displayId, configId, vsyncPeriod);
 }
 
 void Scheduler::dump(ConnectionHandle handle, std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 2fa8b3f..2cdb757 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -74,7 +74,8 @@
     sp<EventThreadConnection> getEventConnection(ConnectionHandle);
 
     void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected);
-    void onConfigChanged(ConnectionHandle, PhysicalDisplayId, HwcConfigIndexType configId);
+    void onConfigChanged(ConnectionHandle, PhysicalDisplayId, HwcConfigIndexType configId,
+                         nsecs_t vsyncPeriod);
 
     void onScreenAcquired(ConnectionHandle);
     void onScreenReleased(ConnectionHandle);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d02d783..8c1d168 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -953,8 +953,11 @@
     ATRACE_INT("ActiveConfigFPS", refreshRate.fps);
 
     if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
+        const nsecs_t vsyncPeriod =
+                mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId)
+                        .vsyncPeriod;
         mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
-                                    mUpcomingActiveConfig.configId);
+                                    mUpcomingActiveConfig.configId, vsyncPeriod);
     }
 }
 
@@ -2688,6 +2691,17 @@
     mRegionSamplingThread =
             new RegionSamplingThread(*this, *mScheduler,
                                      RegionSamplingThread::EnvironmentTimingTunables());
+    // Dispatch a config change request for the primary display on scheduler
+    // initialization, so that the EventThreads always contain a reference to a
+    // prior configuration.
+    //
+    // This is a bit hacky, but this avoids a back-pointer into the main SF
+    // classes from EventThread, and there should be no run-time binder cost
+    // anyway since there are no connected apps at this point.
+    const nsecs_t vsyncPeriod =
+            mRefreshRateConfigs->getRefreshRateFromConfigId(currentConfig).vsyncPeriod;
+    mScheduler->onConfigChanged(mAppConnectionHandle, primaryDisplayId.value, currentConfig,
+                                vsyncPeriod);
 }
 
 void SurfaceFlinger::commitTransaction()
@@ -5577,7 +5591,10 @@
 
         auto configId = HwcConfigIndexType(defaultConfig);
         display->setActiveConfig(configId);
-        mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, configId);
+        const nsecs_t vsyncPeriod =
+                mRefreshRateConfigs->getRefreshRateFromConfigId(configId).vsyncPeriod;
+        mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, configId,
+                                    vsyncPeriod);
         return NO_ERROR;
     }
 
@@ -5601,8 +5618,10 @@
     // TODO(b/140204874): This hack triggers a notification that something has changed, so
     // that listeners that care about a change in allowed configs can get the notification.
     // Giving current ActiveConfig so that most other listeners would just drop the event
+    const nsecs_t vsyncPeriod =
+            mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveConfig()).vsyncPeriod;
     mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
-                                display->getActiveConfig());
+                                display->getActiveConfig(), vsyncPeriod);
 
     if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
         auto configId = mScheduler->getPreferredConfigId();
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 9ad9b91..23df1bb 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -101,6 +101,7 @@
   // length of the shadow to draw around the layer, it may be set on the
   // layer or set by a parent layer.
   float shadow_radius = 49;
+  ColorTransformProto color_transform = 50;
 }
 
 message PositionProto {
@@ -181,3 +182,8 @@
     bool replace_touchable_region_with_crop = 14;
     RectProto touchable_region_crop = 15;
 }
+
+message ColorTransformProto {
+  // This will be a 4x4 matrix of float values
+  repeated float val = 1;
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 420fb29..d51b9a1 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -31,42 +31,40 @@
     void SetUp() override { mDisplayToken = SurfaceComposerClient::getInternalDisplayToken(); }
 
     sp<IBinder> mDisplayToken;
-    int32_t defaultConfigId;
-    float minRefreshRate;
-    float maxRefreshRate;
 };
 
-TEST_F(RefreshRateRangeTest, simpleSetAndGet) {
-    status_t res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, 1, 45, 75);
-    EXPECT_EQ(res, NO_ERROR);
+TEST_F(RefreshRateRangeTest, setAllConfigs) {
+    int32_t initialDefaultConfig;
+    float initialMin;
+    float initialMax;
+    status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
+                                                                       &initialDefaultConfig,
+                                                                       &initialMin, &initialMax);
+    ASSERT_EQ(res, NO_ERROR);
 
-    res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfigId,
-                                                              &minRefreshRate, &maxRefreshRate);
-    EXPECT_EQ(res, NO_ERROR);
-    EXPECT_EQ(defaultConfigId, 1);
-    EXPECT_EQ(minRefreshRate, 45);
-    EXPECT_EQ(maxRefreshRate, 75);
+    Vector<DisplayInfo> configs;
+    res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
+    ASSERT_EQ(res, NO_ERROR);
+
+    for (size_t i = 0; i < configs.size(); i++) {
+        res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i, configs[i].fps,
+                                                                  configs[i].fps);
+        ASSERT_EQ(res, NO_ERROR);
+
+        int defaultConfig;
+        float minFps;
+        float maxFps;
+        res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
+                                                                  &minFps, &maxFps);
+        ASSERT_EQ(res, NO_ERROR);
+        ASSERT_EQ(defaultConfig, i);
+        ASSERT_EQ(minFps, configs[i].fps);
+        ASSERT_EQ(maxFps, configs[i].fps);
+    }
+
+    res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig,
+                                                              initialMin, initialMax);
+    ASSERT_EQ(res, NO_ERROR);
 }
 
-TEST_F(RefreshRateRangeTest, complexSetAndGet) {
-    status_t res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, 1, 45, 75);
-    EXPECT_EQ(res, NO_ERROR);
-
-    res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfigId,
-                                                              &minRefreshRate, &maxRefreshRate);
-    EXPECT_EQ(res, NO_ERROR);
-    EXPECT_EQ(defaultConfigId, 1);
-    EXPECT_EQ(minRefreshRate, 45);
-    EXPECT_EQ(maxRefreshRate, 75);
-
-    // Second call overrides the first one.
-    res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, 10, 145, 875);
-    EXPECT_EQ(res, NO_ERROR);
-    res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfigId,
-                                                              &minRefreshRate, &maxRefreshRate);
-    EXPECT_EQ(res, NO_ERROR);
-    EXPECT_EQ(defaultConfigId, 10);
-    EXPECT_EQ(minRefreshRate, 145);
-    EXPECT_EQ(maxRefreshRate, 875);
-}
 } // namespace android
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 63ae3ae..7786638 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
 {
         "presubmit": {
-            "filter": "*:-RefreshRateRangeTest.*:LayerCallbackTest.MergeBufferNoColor:LayerCallbackTest.MergeNoBufferColor:LayerCallbackTest.MergeOneBufferOneColor:LayerCallbackTest.Merge_SameCallback:LayerCallbackTest.Merge_DifferentClients:LayerCallbackTest.MultipleTransactions_Merge:LayerCallbackTest.MultipleTransactions_Merge_DifferentClients:LayerCallbackTest.MultipleTransactions_Merge_DifferentClients_NoStateChange:LayerCallbackTest.MultipleTransactions_Merge_DifferentClients_SameStateChange:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/3:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/3"
+            "filter": "*:-RefreshRateRangeTest.*:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/3:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/3"
         }
 }
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 80bca02..61d4f47 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -85,7 +85,8 @@
     void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
                                                 bool expectedConnected);
     void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
-                                                      int32_t expectedConfigId);
+                                                      int32_t expectedConfigId,
+                                                      nsecs_t expectedVsyncPeriod);
 
     AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
     AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
@@ -209,13 +210,15 @@
 }
 
 void EventThreadTest::expectConfigChangedEventReceivedByConnection(
-        PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId) {
+        PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId,
+        nsecs_t expectedVsyncPeriod) {
     auto args = mConnectionEventCallRecorder.waitForCall();
     ASSERT_TRUE(args.has_value());
     const auto& event = std::get<0>(args.value());
     EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, event.header.type);
     EXPECT_EQ(expectedDisplayId, event.header.displayId);
     EXPECT_EQ(expectedConfigId, event.config.configId);
+    EXPECT_EQ(expectedVsyncPeriod, event.config.vsyncPeriod);
 }
 
 namespace {
@@ -450,18 +453,18 @@
 }
 
 TEST_F(EventThreadTest, postConfigChangedPrimary) {
-    mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(7));
-    expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7);
+    mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(7), 16666666);
+    expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7, 16666666);
 }
 
 TEST_F(EventThreadTest, postConfigChangedExternal) {
-    mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, HwcConfigIndexType(5));
-    expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5);
+    mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, HwcConfigIndexType(5), 16666666);
+    expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5, 16666666);
 }
 
 TEST_F(EventThreadTest, postConfigChangedPrimary64bit) {
-    mThread->onConfigChanged(DISPLAY_ID_64BIT, HwcConfigIndexType(7));
-    expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7);
+    mThread->onConfigChanged(DISPLAY_ID_64BIT, HwcConfigIndexType(7), 16666666);
+    expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7, 16666666);
 }
 
 TEST_F(EventThreadTest, suppressConfigChanged) {
@@ -470,8 +473,8 @@
             createConnection(suppressConnectionEventRecorder,
                              ISurfaceComposer::eConfigChangedSuppress);
 
-    mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(9));
-    expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9);
+    mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(9), 16666666);
+    expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9, 16666666);
 
     auto args = suppressConnectionEventRecorder.waitForCall();
     ASSERT_FALSE(args.has_value());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index f7c3804..9bda095 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -33,13 +33,14 @@
     MOCK_METHOD0(onScreenReleased, void());
     MOCK_METHOD0(onScreenAcquired, void());
     MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
-    MOCK_METHOD2(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType));
+    MOCK_METHOD3(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType, nsecs_t));
     MOCK_CONST_METHOD1(dump, void(std::string&));
     MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
     MOCK_METHOD1(registerDisplayEventConnection,
                  status_t(const sp<android::EventThreadConnection> &));
     MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
     MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
+    MOCK_METHOD0(requestLatestConfig, void());
     MOCK_METHOD1(pauseVsyncCallback, void(bool));
 };