Merge "Use size_t instead of int for integer_sequence.size()"
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 25c0b19..9aa82d9 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -18,6 +18,9 @@
 
 #include <binder/IServiceManager.h>
 
+#include <inttypes.h>
+#include <unistd.h>
+
 #include <android/os/BnServiceCallback.h>
 #include <android/os/IServiceManager.h>
 #include <binder/IPCThreadState.h>
@@ -36,8 +39,6 @@
 
 #include "Static.h"
 
-#include <unistd.h>
-
 namespace android {
 
 using AidlServiceManager = android::os::IServiceManager;
@@ -219,7 +220,8 @@
 
     const bool isVendorService =
         strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
-    const long timeout = uptimeMillis() + 5000;
+    const long timeout = 5000;
+    int64_t startTime = uptimeMillis();
     // Vendor code can't access system properties
     if (!gSystemBootCompleted && !isVendorService) {
 #ifdef __ANDROID__
@@ -233,15 +235,21 @@
     // retry interval in millisecond; note that vendor services stay at 100ms
     const long sleepTime = gSystemBootCompleted ? 1000 : 100;
 
+    ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
+          ProcessState::self()->getDriverName().c_str());
+
     int n = 0;
-    while (uptimeMillis() < timeout) {
+    while (uptimeMillis() - startTime < timeout) {
         n++;
-        ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
-            ProcessState::self()->getDriverName().c_str());
         usleep(1000*sleepTime);
 
         sp<IBinder> svc = checkService(name);
-        if (svc != nullptr) return svc;
+        if (svc != nullptr) {
+            ALOGI("Waiting for service '%s' on '%s' successful after waiting %" PRIi64 "ms",
+                  String8(name).string(), ProcessState::self()->getDriverName().c_str(),
+                  uptimeMillis() - startTime);
+            return svc;
+        }
     }
     ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
     return nullptr;
diff --git a/libs/binder/include/binder/Parcelable.h b/libs/binder/include/binder/Parcelable.h
index c113279..83c2f19 100644
--- a/libs/binder/include/binder/Parcelable.h
+++ b/libs/binder/include/binder/Parcelable.h
@@ -53,11 +53,20 @@
     // Returns android::OK on success and an appropriate error otherwise.
     virtual status_t readFromParcel(const Parcel* parcel) = 0;
 
-    // 'Stable' means this parcelable is guaranteed to be stable for multiple years.
+    // WARNING: for use by auto-generated code only (AIDL). Should not be used
+    // manually, or there is a risk of breaking CTS, GTS, VTS, or CTS-on-GSI
+    // tests.
+    enum class Stability {
+        STABILITY_LOCAL,
+        STABILITY_VINTF, // corresponds to @VintfStability
+    };
+
+    // 'Stable' means this parcelable is guaranteed to be stable for multiple
+    // years.
     // It must be guaranteed by setting stability field in aidl_interface.
-    // WARNING: isStable() is only expected to be overridden by auto-generated code.
-    // Returns true if this parcelable is stable.
-    virtual bool isStable() const { return false; }
+    // WARNING: getStability() is only expected to be overridden by auto-generated
+    // code. Returns true if this parcelable is stable.
+    virtual Stability getStability() const { return Stability::STABILITY_LOCAL; }
 };  // class Parcelable
 
 #if defined(__clang__)
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 4a4510e..686e274 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -92,6 +92,7 @@
 
     export_shared_lib_headers: [
         "libbinder",
+        "libinput",
     ],
 
     // bufferhub is not used when building libgui for vendors
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 1030b82..117ce58 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -448,19 +448,36 @@
 
 // ------------------------------- InputWindowCommands ----------------------------------------
 
-void InputWindowCommands::merge(const InputWindowCommands& other) {
+bool InputWindowCommands::merge(const InputWindowCommands& other) {
+    bool changes = false;
+#ifndef NO_INPUT
+    changes |= !other.focusRequests.empty();
+    focusRequests.insert(focusRequests.end(), std::make_move_iterator(other.focusRequests.begin()),
+                         std::make_move_iterator(other.focusRequests.end()));
+#endif
+    changes |= other.syncInputWindows && !syncInputWindows;
     syncInputWindows |= other.syncInputWindows;
+    return changes;
 }
 
 void InputWindowCommands::clear() {
+#ifndef NO_INPUT
+    focusRequests.clear();
+#endif
     syncInputWindows = false;
 }
 
 void InputWindowCommands::write(Parcel& output) const {
+#ifndef NO_INPUT
+    output.writeParcelableVector(focusRequests);
+#endif
     output.writeBool(syncInputWindows);
 }
 
 void InputWindowCommands::read(const Parcel& input) {
+#ifndef NO_INPUT
+    input.readParcelableVector(&focusRequests);
+#endif
     syncInputWindows = input.readBool();
 }
 
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index d797a35..229a5c2 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1364,6 +1364,21 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFocusedWindow(
+        const sp<IBinder>& token, const sp<IBinder>& focusedToken, nsecs_t timestampNanos) {
+    FocusRequest request;
+    request.token = token;
+    request.focusedToken = focusedToken;
+    request.timestamp = timestampNanos;
+    return setFocusedWindow(request);
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFocusedWindow(
+        const FocusRequest& request) {
+    mInputWindowCommands.focusRequests.push_back(request);
+    return *this;
+}
+
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() {
     mInputWindowCommands.syncInputWindows = true;
     return *this;
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 00ae220..41aad0d 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -26,6 +26,7 @@
 #include <math/mat4.h>
 
 #ifndef NO_INPUT
+#include <android/FocusRequest.h>
 #include <input/InputWindow.h>
 #endif
 
@@ -283,9 +284,13 @@
 };
 
 struct InputWindowCommands {
+#ifndef NO_INPUT
+    std::vector<FocusRequest> focusRequests;
+#endif
     bool syncInputWindows{false};
 
-    void merge(const InputWindowCommands& other);
+    // Merges the passed in commands and returns true if there were any changes.
+    bool merge(const InputWindowCommands& other);
     void clear();
     void write(Parcel& output) const;
     void read(const Parcel& input);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index eb757ba..d5ca0f6 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -507,6 +507,9 @@
 
 #ifndef NO_INPUT
         Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
+        Transaction& setFocusedWindow(const sp<IBinder>& token, const sp<IBinder>& focusedToken,
+                                      nsecs_t timestampNanos);
+        Transaction& setFocusedWindow(const FocusRequest& request);
         Transaction& syncInputWindows();
 #endif
 
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 8a9f261..7dd5276 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -60,6 +60,7 @@
                 "LatencyStatistics.cpp",
                 "VelocityControl.cpp",
                 "VelocityTracker.cpp",
+                "android/FocusRequest.aidl",
                 "android/os/IInputFlinger.aidl",
                 "android/os/ISetInputWindowsListener.aidl",
             ],
diff --git a/libs/input/android/FocusRequest.aidl b/libs/input/android/FocusRequest.aidl
new file mode 100644
index 0000000..a5034a4
--- /dev/null
+++ b/libs/input/android/FocusRequest.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android;
+
+/** @hide */
+parcelable FocusRequest {
+    /**
+     * Input channel token used to identify the window that should gain focus.
+     */
+    IBinder token;
+    /**
+     * The token that the caller expects currently to be focused. If the
+     * specified token does not match the currently focused window, this request will be dropped.
+     * If the specified focused token matches the currently focused window, the call will succeed.
+     * Set this to "null" if this call should succeed no matter what the currently focused token
+     * is.
+     */
+    @nullable IBinder focusedToken;
+    /**
+     * SYSTEM_TIME_MONOTONIC timestamp in nanos set by the client (wm) when requesting the focus
+     * change. This determines which request gets precedence if there is a focus change request
+     * from another source such as pointer down.
+     */
+    long timestamp;
+}
diff --git a/libs/input/android/os/IInputFlinger.aidl b/libs/input/android/os/IInputFlinger.aidl
index 44bb66d..5eefad3 100644
--- a/libs/input/android/os/IInputFlinger.aidl
+++ b/libs/input/android/os/IInputFlinger.aidl
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.FocusRequest;
 import android.InputChannel;
 import android.InputWindowInfo;
 import android.os.ISetInputWindowsListener;
@@ -31,4 +32,9 @@
             in @nullable ISetInputWindowsListener setInputWindowsListener);
     void registerInputChannel(in InputChannel channel);
     void unregisterInputChannel(in InputChannel channel);
+    /**
+     * Sets focus to the window identified by the token. This must be called
+     * after updating any input window handles.
+     */
+    oneway void setFocusedWindow(in FocusRequest request);
 }
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 088c6f1..e49667e 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -146,4 +146,9 @@
     return NO_ERROR;
 }
 
+binder::Status InputManager::setFocusedWindow(const FocusRequest& request) {
+    mDispatcher->setFocusedWindow(request);
+    return binder::Status::ok();
+}
+
 } // namespace android
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 0503e81..bf86a98 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -110,6 +110,7 @@
 
     binder::Status registerInputChannel(const InputChannel& channel) override;
     binder::Status unregisterInputChannel(const InputChannel& channel) override;
+    binder::Status setFocusedWindow(const FocusRequest&) override;
 
 private:
     sp<InputReaderInterface> mReader;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index bfaab3c..82e0a4e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -5175,4 +5175,19 @@
     return result == std::cv_status::no_timeout;
 }
 
+/**
+ * Sets focus to the window identified by the token. This must be called
+ * after updating any input window handles.
+ *
+ * Params:
+ *  request.token - input channel token used to identify the window that should gain focus.
+ *  request.focusedToken - the token that the caller expects currently to be focused. If the
+ *  specified token does not match the currently focused window, this request will be dropped.
+ *  If the specified focused token matches the currently focused window, the call will succeed.
+ *  Set this to "null" if this call should succeed no matter what the currently focused token is.
+ *  request.timestamp - SYSTEM_TIME_MONOTONIC timestamp in nanos set by the client (wm)
+ *  when requesting the focus change. This determines which request gets
+ *  precedence if there is a focus change request from another source such as pointer down.
+ */
+void InputDispatcher::setFocusedWindow(const FocusRequest&) {}
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index ba7ace0..b4d1079 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -126,6 +126,7 @@
 
     virtual status_t registerInputChannel(
             const std::shared_ptr<InputChannel>& inputChannel) override;
+    virtual void setFocusedWindow(const FocusRequest&) override;
     virtual status_t registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
                                           int32_t displayId, bool isGestureMonitor) override;
     virtual status_t unregisterInputChannel(const InputChannel& inputChannel) override;
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 272b0a6..f97c880 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -18,6 +18,7 @@
 #define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H
 
 #include <InputListener.h>
+#include <android/FocusRequest.h>
 #include <android/os/ISetInputWindowsListener.h>
 #include <input/InputApplication.h>
 #include <input/InputTransport.h>
@@ -148,6 +149,11 @@
      */
     virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
 
+    /**
+     * Sets focus on the specified window.
+     */
+    virtual void setFocusedWindow(const FocusRequest&) = 0;
+
     /* Registers input channels that may be used as targets for input events.
      *
      * This method may be called on any thread (usually by the input manager).
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index cd655e0..2a2cea5 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -50,6 +50,7 @@
     }
     binder::Status registerInputChannel(const InputChannel&) { return binder::Status::ok(); }
     binder::Status unregisterInputChannel(const InputChannel&) { return binder::Status::ok(); }
+    binder::Status setFocusedWindow(const FocusRequest&) { return binder::Status::ok(); }
 
 private:
     virtual ~InputFlinger();
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index eb9ac68..6465cc9 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -30,14 +30,14 @@
         "AnrTracker_test.cpp",
         "BlockingQueue_test.cpp",
         "EventHub_test.cpp",
-        "TestInputListener.cpp",
+        "IInputFlingerQuery.aidl",
         "InputClassifier_test.cpp",
         "InputClassifierConverter_test.cpp",
         "InputDispatcher_test.cpp",
         "InputReader_test.cpp",
         "InputFlingerService_test.cpp",
+        "TestInputListener.cpp",
         "UinputDevice.cpp",
-        "IInputFlingerQuery.aidl"
     ],
     aidl: {
         include_dirs: [
diff --git a/services/inputflinger/tests/IInputFlingerQuery.aidl b/services/inputflinger/tests/IInputFlingerQuery.aidl
index 755373b..b5c5c9e 100644
--- a/services/inputflinger/tests/IInputFlingerQuery.aidl
+++ b/services/inputflinger/tests/IInputFlingerQuery.aidl
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.FocusRequest;
 import android.InputChannel;
 import android.InputWindowInfo;
 import android.os.ISetInputWindowsListener;
@@ -24,4 +25,5 @@
     /* Test interfaces */
     void getInputWindows(out InputWindowInfo[] inputHandles);
     void getInputChannels(out InputChannel[] channels);
+    void getLastFocusRequest(out FocusRequest request);
 }
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
index ce82d28..d6543f2 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -55,6 +55,7 @@
 namespace android {
 
 static const sp<IBinder> TestInfoToken = new BBinder();
+static const sp<IBinder> FocusedTestInfoToken = new BBinder();
 static constexpr int32_t TestInfoId = 1;
 static const std::string TestInfoName = "InputFlingerServiceTestInputWindowInfo";
 static constexpr Flags<InputWindowInfo::Flag> TestInfoFlags = InputWindowInfo::Flag::NOT_FOCUSABLE;
@@ -102,7 +103,9 @@
 
 protected:
     void InitializeInputFlinger();
-    void setInputWindowsByInfos(std::vector<InputWindowInfo>& infos);
+    void setInputWindowsByInfos(const std::vector<InputWindowInfo>& infos);
+    void setFocusedWindow(const sp<IBinder> token, const sp<IBinder> focusedToken,
+                          nsecs_t timestampNanos);
 
     void setInputWindowsFinished();
     void verifyInputWindowInfo(const InputWindowInfo& info) const;
@@ -137,6 +140,7 @@
 
     binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles);
     binder::Status getInputChannels(std::vector<::android::InputChannel>* channels);
+    binder::Status getLastFocusRequest(FocusRequest*);
 
     status_t dump(int fd, const Vector<String16>& args) override;
 
@@ -146,11 +150,13 @@
 
     binder::Status registerInputChannel(const InputChannel& channel) override;
     binder::Status unregisterInputChannel(const InputChannel& channel) override;
+    binder::Status setFocusedWindow(const FocusRequest&) override;
 
 private:
     mutable Mutex mLock;
     std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mHandlesPerDisplay;
     std::vector<std::shared_ptr<InputChannel>> mInputChannels;
+    FocusRequest mFocusRequest;
 };
 
 class TestInputQuery : public BnInputFlingerQuery {
@@ -158,6 +164,7 @@
     TestInputQuery(sp<android::TestInputManager> manager) : mManager(manager){};
     binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles) override;
     binder::Status getInputChannels(std::vector<::android::InputChannel>* channels) override;
+    binder::Status getLastFocusRequest(FocusRequest*) override;
 
 private:
     sp<android::TestInputManager> mManager;
@@ -172,6 +179,10 @@
     return mManager->getInputChannels(channels);
 }
 
+binder::Status TestInputQuery::getLastFocusRequest(FocusRequest* request) {
+    return mManager->getLastFocusRequest(request);
+}
+
 binder::Status SetInputWindowsListener::onSetInputWindowsFinished() {
     if (mCbFunc != nullptr) {
         mCbFunc();
@@ -251,6 +262,16 @@
     return binder::Status::ok();
 }
 
+binder::Status TestInputManager::getLastFocusRequest(FocusRequest* request) {
+    *request = mFocusRequest;
+    return binder::Status::ok();
+}
+
+binder::Status TestInputManager::setFocusedWindow(const FocusRequest& request) {
+    mFocusRequest = request;
+    return binder::Status::ok();
+}
+
 void InputFlingerServiceTest::SetUp() {
     mSetInputWindowsListener = new SetInputWindowsListener([&]() {
         std::unique_lock<std::mutex> lock(mLock);
@@ -310,13 +331,25 @@
     mQuery = interface_cast<IInputFlingerQuery>(input);
 }
 
-void InputFlingerServiceTest::setInputWindowsByInfos(std::vector<InputWindowInfo>& infos) {
+void InputFlingerServiceTest::setInputWindowsByInfos(const std::vector<InputWindowInfo>& infos) {
     std::unique_lock<std::mutex> lock(mLock);
     mService->setInputWindows(infos, mSetInputWindowsListener);
     // Verify listener call
     EXPECT_NE(mSetInputWindowsFinishedCondition.wait_for(lock, 1s), std::cv_status::timeout);
 }
 
+void InputFlingerServiceTest::setFocusedWindow(const sp<IBinder> token,
+                                               const sp<IBinder> focusedToken,
+                                               nsecs_t timestampNanos) {
+    FocusRequest request;
+    request.token = TestInfoToken;
+    request.focusedToken = focusedToken;
+    request.timestamp = timestampNanos;
+    mService->setFocusedWindow(request);
+    // call set input windows and wait for the callback to drain the queue.
+    setInputWindowsByInfos(std::vector<InputWindowInfo>());
+}
+
 /**
  *  Test InputFlinger service interface SetInputWindows
  */
@@ -376,6 +409,30 @@
     EXPECT_EQ(channels.size(), 0UL);
 }
 
+TEST_F(InputFlingerServiceTest, InputWindow_setFocusedWindow) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    setFocusedWindow(TestInfoToken, nullptr /* focusedToken */, now);
+
+    FocusRequest request;
+    mQuery->getLastFocusRequest(&request);
+
+    EXPECT_EQ(request.token, TestInfoToken);
+    EXPECT_EQ(request.focusedToken, nullptr);
+    EXPECT_EQ(request.timestamp, now);
+}
+
+TEST_F(InputFlingerServiceTest, InputWindow_setFocusedWindowWithFocusedToken) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    setFocusedWindow(TestInfoToken, FocusedTestInfoToken, now);
+
+    FocusRequest request;
+    mQuery->getLastFocusRequest(&request);
+
+    EXPECT_EQ(request.token, TestInfoToken);
+    EXPECT_EQ(request.focusedToken, FocusedTestInfoToken);
+    EXPECT_EQ(request.timestamp, now);
+}
+
 } // namespace android
 
 int main(int argc, char** argv) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7d5cb67..3b562bf 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2932,6 +2932,10 @@
     mInputFlinger->setInputWindows(inputInfos,
                                mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener
                                                                      : nullptr);
+    for (const auto& focusRequest : mInputWindowCommands.focusRequests) {
+        mInputFlinger->setFocusedWindow(focusRequest);
+    }
+    mInputWindowCommands.focusRequests.clear();
 }
 
 void SurfaceFlinger::commitInputWindowCommands() {
@@ -3922,13 +3926,8 @@
 }
 
 uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) {
-    uint32_t flags = 0;
-    if (inputWindowCommands.syncInputWindows) {
-        flags |= eTraversalNeeded;
-    }
-
-    mPendingInputWindowCommands.merge(inputWindowCommands);
-    return flags;
+    const bool hasChanges = mPendingInputWindowCommands.merge(inputWindowCommands);
+    return hasChanges ? eTraversalNeeded : 0;
 }
 
 status_t SurfaceFlinger::mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,