Move things in InputWindowInfo to enum classes

Also introduce a new Flag class to make it possible to deal with flags
while treating the individual flags as part of an enum class in a type
safe manner.

Bug: 160010896
Test: atest inputflinger_tests, atest libinput_tests
Change-Id: I915a1c1e3b31f1c0fd99b83ba5fad7e537cd6f84
diff --git a/include/input/Flags.h b/include/input/Flags.h
new file mode 100644
index 0000000..f3198c9
--- /dev/null
+++ b/include/input/Flags.h
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+#include <android-base/stringprintf.h>
+
+#include <cstdint>
+#include <optional>
+#include <string>
+#include <type_traits>
+
+#include "utils/BitSet.h"
+
+#ifndef __UI_INPUT_FLAGS_H
+#define __UI_INPUT_FLAGS_H
+
+namespace android {
+
+// A trait for determining whether a type is specifically an enum class or not.
+template <typename T, bool = std::is_enum_v<T>>
+struct is_enum_class : std::false_type {};
+
+// By definition, an enum class is an enum that is not implicitly convertible to its underlying
+// type.
+template <typename T>
+struct is_enum_class<T, true>
+      : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {};
+
+template <typename T>
+inline constexpr bool is_enum_class_v = is_enum_class<T>::value;
+
+/* A class for handling flags defined by an enum or enum class in a type-safe way. */
+template <class F, typename = std::enable_if_t<std::is_enum_v<F>>>
+class Flags {
+    // F must be an enum or its underlying type is undefined. Theoretically we could specialize this
+    // further to avoid this restriction but in general we want to encourage the use of enums
+    // anyways.
+    using U = typename std::underlying_type_t<F>;
+
+public:
+    constexpr Flags(F f) : flags(static_cast<U>(f)) {}
+    constexpr Flags() : flags(0) {}
+    constexpr Flags(const Flags<F>& f) : flags(f.flags) {}
+
+    // Provide a non-explicit construct for non-enum classes since they easily convert to their
+    // underlying types (e.g. when used with bitwise operators). For enum classes, however, we
+    // should force them to be explicitly constructed from their underlying types to make full use
+    // of the type checker.
+    template <typename T = U>
+    constexpr Flags(T t, typename std::enable_if_t<!is_enum_class_v<F>, T>* = nullptr) : flags(t) {}
+    template <typename T = U>
+    explicit constexpr Flags(T t, typename std::enable_if_t<is_enum_class_v<F>, T>* = nullptr)
+          : flags(t) {}
+    /*
+     * Tests whether the given flag is set.
+     */
+    bool test(F flag) const {
+        U f = static_cast<U>(flag);
+        return (f & flags) == f;
+    }
+
+    /* Tests whether any of the given flags are set */
+    bool any(Flags<F> f) { return (flags & f.flags) != 0; }
+
+    /* Tests whether all of the given flags are set */
+    bool all(Flags<F> f) { return (flags & f.flags) == f.flags; }
+
+    Flags<F> operator|(Flags<F> rhs) const { return static_cast<F>(flags | rhs.flags); }
+    Flags<F>& operator|=(Flags<F> rhs) {
+        flags = flags | rhs.flags;
+        return *this;
+    }
+
+    Flags<F> operator&(Flags<F> rhs) const { return static_cast<F>(flags & rhs.flags); }
+    Flags<F>& operator&=(Flags<F> rhs) {
+        flags = flags & rhs.flags;
+        return *this;
+    }
+
+    Flags<F> operator^(Flags<F> rhs) const { return static_cast<F>(flags ^ rhs.flags); }
+    Flags<F>& operator^=(Flags<F> rhs) {
+        flags = flags ^ rhs.flags;
+        return *this;
+    }
+
+    Flags<F> operator~() { return static_cast<F>(~flags); }
+
+    bool operator==(Flags<F> rhs) const { return flags == rhs.flags; }
+    bool operator!=(Flags<F> rhs) const { return !operator==(rhs); }
+
+    Flags<F>& operator=(const Flags<F>& rhs) {
+        flags = rhs.flags;
+        return *this;
+    }
+
+    /*
+     * Returns the stored set of flags.
+     *
+     * Note that this returns the underlying type rather than the base enum class. This is because
+     * the value is no longer necessarily a strict member of the enum since the returned value could
+     * be multiple enum variants OR'd together.
+     */
+    U get() const { return flags; }
+
+    std::string string() const { return string(defaultStringify); }
+
+    std::string string(std::function<std::optional<std::string>(F)> stringify) const {
+        // The type can't be larger than 64-bits otherwise it won't fit in BitSet64.
+        static_assert(sizeof(U) <= sizeof(uint64_t));
+        std::string result;
+        bool first = true;
+        U unstringified = 0;
+        for (BitSet64 bits(flags); !bits.isEmpty();) {
+            uint64_t bit = bits.clearLastMarkedBit(); // counts from left
+            const U flag = 1 << (64 - bit - 1);
+            std::optional<std::string> flagString = stringify(static_cast<F>(flag));
+            if (flagString) {
+                appendFlag(result, flagString.value(), first);
+            } else {
+                unstringified |= flag;
+            }
+        }
+
+        if (unstringified != 0) {
+            appendFlag(result, base::StringPrintf("0x%08x", unstringified), first);
+        }
+
+        if (first) {
+            result += "0x0";
+        }
+
+        return result;
+    }
+
+private:
+    U flags;
+
+    static std::optional<std::string> defaultStringify(F) { return std::nullopt; }
+    static void appendFlag(std::string& str, const std::string& flag, bool& first) {
+        if (first) {
+            first = false;
+        } else {
+            str += " | ";
+        }
+        str += flag;
+    }
+};
+
+// This namespace provides operator overloads for enum classes to make it easier to work with them
+// as flags. In order to use these, add them via a `using namespace` declaration.
+namespace flag_operators {
+
+template <typename F, typename = std::enable_if_t<is_enum_class_v<F>>>
+inline Flags<F> operator~(F f) {
+    using U = typename std::underlying_type_t<F>;
+    return static_cast<F>(~static_cast<U>(f));
+}
+template <typename F, typename = std::enable_if_t<is_enum_class_v<F>>>
+Flags<F> operator|(F lhs, F rhs) {
+    using U = typename std::underlying_type_t<F>;
+    return static_cast<F>(static_cast<U>(lhs) | static_cast<U>(rhs));
+}
+
+} // namespace flag_operators
+} // namespace android
+
+#endif // __UI_INPUT_FLAGS_H
\ No newline at end of file
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 18cca2c..233c7ae 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -19,6 +19,7 @@
 
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
+#include <input/Flags.h>
 #include <input/Input.h>
 #include <input/InputTransport.h>
 #include <ui/Rect.h>
@@ -38,92 +39,92 @@
     InputWindowInfo() = default;
 
     // Window flags from WindowManager.LayoutParams
-    enum : uint32_t {
-        FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
-        FLAG_DIM_BEHIND = 0x00000002,
-        FLAG_BLUR_BEHIND = 0x00000004,
-        FLAG_NOT_FOCUSABLE = 0x00000008,
-        FLAG_NOT_TOUCHABLE = 0x00000010,
-        FLAG_NOT_TOUCH_MODAL = 0x00000020,
-        FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040,
-        FLAG_KEEP_SCREEN_ON = 0x00000080,
-        FLAG_LAYOUT_IN_SCREEN = 0x00000100,
-        FLAG_LAYOUT_NO_LIMITS = 0x00000200,
-        FLAG_FULLSCREEN = 0x00000400,
-        FLAG_FORCE_NOT_FULLSCREEN = 0x00000800,
-        FLAG_DITHER = 0x00001000,
-        FLAG_SECURE = 0x00002000,
-        FLAG_SCALED = 0x00004000,
-        FLAG_IGNORE_CHEEK_PRESSES = 0x00008000,
-        FLAG_LAYOUT_INSET_DECOR = 0x00010000,
-        FLAG_ALT_FOCUSABLE_IM = 0x00020000,
-        FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000,
-        FLAG_SHOW_WHEN_LOCKED = 0x00080000,
-        FLAG_SHOW_WALLPAPER = 0x00100000,
-        FLAG_TURN_SCREEN_ON = 0x00200000,
-        FLAG_DISMISS_KEYGUARD = 0x00400000,
-        FLAG_SPLIT_TOUCH = 0x00800000,
-        FLAG_HARDWARE_ACCELERATED = 0x01000000,
-        FLAG_LAYOUT_IN_OVERSCAN = 0x02000000,
-        FLAG_TRANSLUCENT_STATUS = 0x04000000,
-        FLAG_TRANSLUCENT_NAVIGATION = 0x08000000,
-        FLAG_LOCAL_FOCUS_MODE = 0x10000000,
-        FLAG_SLIPPERY = 0x20000000,
-        FLAG_LAYOUT_ATTACHED_IN_DECOR = 0x40000000,
-        FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000,
-    };
+    enum class Flag : uint32_t {
+        ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
+        DIM_BEHIND = 0x00000002,
+        BLUR_BEHIND = 0x00000004,
+        NOT_FOCUSABLE = 0x00000008,
+        NOT_TOUCHABLE = 0x00000010,
+        NOT_TOUCH_MODAL = 0x00000020,
+        TOUCHABLE_WHEN_WAKING = 0x00000040,
+        KEEP_SCREEN_ON = 0x00000080,
+        LAYOUT_IN_SCREEN = 0x00000100,
+        LAYOUT_NO_LIMITS = 0x00000200,
+        FULLSCREEN = 0x00000400,
+        FORCE_NOT_FULLSCREEN = 0x00000800,
+        DITHER = 0x00001000,
+        SECURE = 0x00002000,
+        SCALED = 0x00004000,
+        IGNORE_CHEEK_PRESSES = 0x00008000,
+        LAYOUT_INSET_DECOR = 0x00010000,
+        ALT_FOCUSABLE_IM = 0x00020000,
+        WATCH_OUTSIDE_TOUCH = 0x00040000,
+        SHOW_WHEN_LOCKED = 0x00080000,
+        SHOW_WALLPAPER = 0x00100000,
+        TURN_SCREEN_ON = 0x00200000,
+        DISMISS_KEYGUARD = 0x00400000,
+        SPLIT_TOUCH = 0x00800000,
+        HARDWARE_ACCELERATED = 0x01000000,
+        LAYOUT_IN_OVERSCAN = 0x02000000,
+        TRANSLUCENT_STATUS = 0x04000000,
+        TRANSLUCENT_NAVIGATION = 0x08000000,
+        LOCAL_FOCUS_MODE = 0x10000000,
+        SLIPPERY = 0x20000000,
+        LAYOUT_ATTACHED_IN_DECOR = 0x40000000,
+        DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000,
+    }; // Window types from WindowManager.LayoutParams
 
-    // Window types from WindowManager.LayoutParams
-    enum {
+    enum class Type : int32_t {
+        UNKNOWN = 0,
         FIRST_APPLICATION_WINDOW = 1,
-        TYPE_BASE_APPLICATION = 1,
-        TYPE_APPLICATION = 2,
-        TYPE_APPLICATION_STARTING = 3,
+        BASE_APPLICATION = 1,
+        APPLICATION = 2,
+        APPLICATION_STARTING = 3,
         LAST_APPLICATION_WINDOW = 99,
         FIRST_SUB_WINDOW = 1000,
-        TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW,
-        TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1,
-        TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2,
-        TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3,
-        TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4,
+        APPLICATION_PANEL = FIRST_SUB_WINDOW,
+        APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1,
+        APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2,
+        APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3,
+        APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4,
         LAST_SUB_WINDOW = 1999,
         FIRST_SYSTEM_WINDOW = 2000,
-        TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW,
-        TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW + 1,
-        TYPE_PHONE = FIRST_SYSTEM_WINDOW + 2,
-        TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3,
-        TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW + 4,
-        TYPE_TOAST = FIRST_SYSTEM_WINDOW + 5,
-        TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6,
-        TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7,
-        TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW + 8,
-        TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW + 9,
-        TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10,
-        TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11,
-        TYPE_INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW + 12,
-        TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW + 13,
-        TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW + 14,
-        TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 15,
-        TYPE_DRAG = FIRST_SYSTEM_WINDOW + 16,
-        TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW + 17,
-        TYPE_POINTER = FIRST_SYSTEM_WINDOW + 18,
-        TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19,
-        TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW + 20,
-        TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW + 21,
-        TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW + 22,
-        TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW + 24,
-        TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27,
-        TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32,
-        TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34,
-        TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39,
-        TYPE_NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40,
+        STATUS_BAR = FIRST_SYSTEM_WINDOW,
+        SEARCH_BAR = FIRST_SYSTEM_WINDOW + 1,
+        PHONE = FIRST_SYSTEM_WINDOW + 2,
+        SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3,
+        KEYGUARD = FIRST_SYSTEM_WINDOW + 4,
+        TOAST = FIRST_SYSTEM_WINDOW + 5,
+        SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6,
+        PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7,
+        SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW + 8,
+        KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW + 9,
+        SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10,
+        INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11,
+        INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW + 12,
+        WALLPAPER = FIRST_SYSTEM_WINDOW + 13,
+        STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW + 14,
+        SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 15,
+        DRAG = FIRST_SYSTEM_WINDOW + 16,
+        STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW + 17,
+        POINTER = FIRST_SYSTEM_WINDOW + 18,
+        NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19,
+        VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW + 20,
+        BOOT_PROGRESS = FIRST_SYSTEM_WINDOW + 21,
+        INPUT_CONSUMER = FIRST_SYSTEM_WINDOW + 22,
+        NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW + 24,
+        MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27,
+        ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32,
+        DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34,
+        ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39,
+        NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40,
         LAST_SYSTEM_WINDOW = 2999,
     };
 
-    enum {
-        INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES = 0x00000001,
-        INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002,
-        INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004,
+    enum class Feature {
+        DISABLE_TOUCH_PAD_GESTURES = 0x00000001,
+        NO_INPUT_CHANNEL = 0x00000002,
+        DISABLE_USER_ACTIVITY = 0x00000004,
     };
 
     /* These values are filled in by the WM and passed through SurfaceFlinger
@@ -135,8 +136,8 @@
     // This uniquely identifies the input window.
     int32_t id = -1;
     std::string name;
-    int32_t layoutParamsFlags = 0;
-    int32_t layoutParamsType = 0;
+    Flags<Flag> flags;
+    Type type = Type::UNKNOWN;
     std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5);
 
     /* These values are filled in by SurfaceFlinger. */
@@ -182,7 +183,7 @@
     bool trustedOverlay = false;
     int32_t ownerPid = -1;
     int32_t ownerUid = -1;
-    int32_t inputFeatures = 0;
+    Flags<Feature> inputFeatures;
     int32_t displayId = ADISPLAY_ID_NONE;
     int32_t portalToDisplayId = ADISPLAY_ID_NONE;
     InputApplicationInfo applicationInfo;
@@ -204,9 +205,9 @@
     status_t writeToParcel(android::Parcel* parcel) const override;
 
     status_t readFromParcel(const android::Parcel* parcel) override;
-};
 
-std::string inputWindowFlagsToString(uint32_t flags);
+    static std::optional<std::string> flagToString(Flag f);
+};
 
 /*
  * Handle for a window that can receive input.
@@ -267,7 +268,6 @@
 
     InputWindowInfo mInfo;
 };
-
 } // namespace android
 
 #endif // _UI_INPUT_WINDOW_H
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 152f7ad..383d591 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -186,8 +186,8 @@
     void populateInputInfo(int width, int height) {
         mInputInfo.token = mServerChannel->getConnectionToken();
         mInputInfo.name = "Test info";
-        mInputInfo.layoutParamsFlags = InputWindowInfo::FLAG_NOT_TOUCH_MODAL;
-        mInputInfo.layoutParamsType = InputWindowInfo::TYPE_BASE_APPLICATION;
+        mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL;
+        mInputInfo.type = InputWindowInfo::Type::BASE_APPLICATION;
         mInputInfo.dispatchingTimeout = 5s;
         mInputInfo.globalScaleFactor = 1.0;
         mInputInfo.canReceiveKeys = true;
@@ -200,7 +200,6 @@
         // TODO: Fill in from SF?
         mInputInfo.ownerPid = 11111;
         mInputInfo.ownerUid = 11111;
-        mInputInfo.inputFeatures = 0;
         mInputInfo.displayId = 0;
 
         InputApplicationInfo aInfo;
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index ae9b3f0..36c1f80 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <type_traits>
 #define LOG_TAG "InputWindow"
 #define LOG_NDEBUG 0
 
@@ -26,117 +27,6 @@
 
 namespace android {
 
-const char* inputWindowFlagToString(uint32_t flag) {
-    switch (flag) {
-        case InputWindowInfo::FLAG_ALLOW_LOCK_WHILE_SCREEN_ON: {
-            return "ALLOW_LOCK_WHILE_SCREEN_ON";
-        }
-        case InputWindowInfo::FLAG_DIM_BEHIND: {
-            return "DIM_BEHIND";
-        }
-        case InputWindowInfo::FLAG_BLUR_BEHIND: {
-            return "BLUR_BEHIND";
-        }
-        case InputWindowInfo::FLAG_NOT_FOCUSABLE: {
-            return "NOT_FOCUSABLE";
-        }
-        case InputWindowInfo::FLAG_NOT_TOUCHABLE: {
-            return "NOT_TOUCHABLE";
-        }
-        case InputWindowInfo::FLAG_NOT_TOUCH_MODAL: {
-            return "NOT_TOUCH_MODAL";
-        }
-        case InputWindowInfo::FLAG_TOUCHABLE_WHEN_WAKING: {
-            return "TOUCHABLE_WHEN_WAKING";
-        }
-        case InputWindowInfo::FLAG_KEEP_SCREEN_ON: {
-            return "KEEP_SCREEN_ON";
-        }
-        case InputWindowInfo::FLAG_LAYOUT_IN_SCREEN: {
-            return "LAYOUT_IN_SCREEN";
-        }
-        case InputWindowInfo::FLAG_LAYOUT_NO_LIMITS: {
-            return "LAYOUT_NO_LIMITS";
-        }
-        case InputWindowInfo::FLAG_FULLSCREEN: {
-            return "FULLSCREEN";
-        }
-        case InputWindowInfo::FLAG_FORCE_NOT_FULLSCREEN: {
-            return "FORCE_NOT_FULLSCREEN";
-        }
-        case InputWindowInfo::FLAG_DITHER: {
-            return "DITHER";
-        }
-        case InputWindowInfo::FLAG_SECURE: {
-            return "SECURE";
-        }
-        case InputWindowInfo::FLAG_SCALED: {
-            return "SCALED";
-        }
-        case InputWindowInfo::FLAG_IGNORE_CHEEK_PRESSES: {
-            return "IGNORE_CHEEK_PRESSES";
-        }
-        case InputWindowInfo::FLAG_LAYOUT_INSET_DECOR: {
-            return "LAYOUT_INSET_DECOR";
-        }
-        case InputWindowInfo::FLAG_ALT_FOCUSABLE_IM: {
-            return "ALT_FOCUSABLE_IM";
-        }
-        case InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH: {
-            return "WATCH_OUTSIDE_TOUCH";
-        }
-        case InputWindowInfo::FLAG_SHOW_WHEN_LOCKED: {
-            return "SHOW_WHEN_LOCKED";
-        }
-        case InputWindowInfo::FLAG_SHOW_WALLPAPER: {
-            return "SHOW_WALLPAPER";
-        }
-        case InputWindowInfo::FLAG_TURN_SCREEN_ON: {
-            return "TURN_SCREEN_ON";
-        }
-        case InputWindowInfo::FLAG_DISMISS_KEYGUARD: {
-            return "DISMISS_KEYGUARD";
-        }
-        case InputWindowInfo::FLAG_SPLIT_TOUCH: {
-            return "SPLIT_TOUCH";
-        }
-        case InputWindowInfo::FLAG_HARDWARE_ACCELERATED: {
-            return "HARDWARE_ACCELERATED";
-        }
-        case InputWindowInfo::FLAG_LAYOUT_IN_OVERSCAN: {
-            return "LAYOUT_IN_OVERSCAN";
-        }
-        case InputWindowInfo::FLAG_TRANSLUCENT_STATUS: {
-            return "TRANSLUCENT_STATUS";
-        }
-        case InputWindowInfo::FLAG_TRANSLUCENT_NAVIGATION: {
-            return "TRANSLUCENT_NAVIGATION";
-        }
-        case InputWindowInfo::FLAG_LOCAL_FOCUS_MODE: {
-            return "LOCAL_FOCUS_MODE";
-        }
-        case InputWindowInfo::FLAG_SLIPPERY: {
-            return "SLIPPERY";
-        }
-        case InputWindowInfo::FLAG_LAYOUT_ATTACHED_IN_DECOR: {
-            return "LAYOUT_ATTACHED_IN_DECOR";
-        }
-        case InputWindowInfo::FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS: {
-            return "DRAWS_SYSTEM_BAR_BACKGROUNDS";
-        }
-    }
-    return "UNKNOWN";
-}
-
-std::string inputWindowFlagsToString(uint32_t flags) {
-    std::string result;
-    for (BitSet32 bits(flags); !bits.isEmpty();) {
-        uint32_t bit = bits.clearLastMarkedBit(); // counts from left
-        const uint32_t flag = 1 << (32 - bit - 1);
-        result += android::base::StringPrintf("%s | ", inputWindowFlagToString(flag));
-    }
-    return result;
-}
 
 // --- InputWindowInfo ---
 void InputWindowInfo::addTouchableRegion(const Rect& region) {
@@ -153,7 +43,7 @@
 }
 
 bool InputWindowInfo::supportsSplitTouch() const {
-    return layoutParamsFlags & FLAG_SPLIT_TOUCH;
+    return flags.test(Flag::SPLIT_TOUCH);
 }
 
 bool InputWindowInfo::overlaps(const InputWindowInfo* other) const {
@@ -162,14 +52,12 @@
 }
 
 bool InputWindowInfo::operator==(const InputWindowInfo& info) const {
-    return info.token == token && info.id == id && info.name == name &&
-            info.layoutParamsFlags == layoutParamsFlags &&
-            info.layoutParamsType == layoutParamsType &&
-            info.dispatchingTimeout == dispatchingTimeout && info.frameLeft == frameLeft &&
-            info.frameTop == frameTop && info.frameRight == frameRight &&
-            info.frameBottom == frameBottom && info.surfaceInset == surfaceInset &&
-            info.globalScaleFactor == globalScaleFactor && info.windowXScale == windowXScale &&
-            info.windowYScale == windowYScale &&
+    return info.token == token && info.id == id && info.name == name && info.flags == flags &&
+            info.type == type && info.dispatchingTimeout == dispatchingTimeout &&
+            info.frameLeft == frameLeft && info.frameTop == frameTop &&
+            info.frameRight == frameRight && info.frameBottom == frameBottom &&
+            info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor &&
+            info.windowXScale == windowXScale && info.windowYScale == windowYScale &&
             info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible &&
             info.canReceiveKeys == canReceiveKeys && info.trustedOverlay == trustedOverlay &&
             info.hasFocus == hasFocus && info.hasWallpaper == hasWallpaper &&
@@ -197,8 +85,8 @@
         parcel->writeInt64(dispatchingTimeout.count()) ?:
         parcel->writeInt32(id) ?:
         parcel->writeUtf8AsUtf16(name) ?:
-        parcel->writeInt32(layoutParamsFlags) ?:
-        parcel->writeInt32(layoutParamsType) ?:
+        parcel->writeInt32(flags.get()) ?:
+        parcel->writeInt32(static_cast<std::underlying_type_t<InputWindowInfo::Type>>(type)) ?:
         parcel->writeInt32(frameLeft) ?:
         parcel->writeInt32(frameTop) ?:
         parcel->writeInt32(frameRight) ?:
@@ -215,7 +103,7 @@
         parcel->writeBool(trustedOverlay) ?:
         parcel->writeInt32(ownerPid) ?:
         parcel->writeInt32(ownerUid) ?:
-        parcel->writeInt32(inputFeatures) ?:
+        parcel->writeInt32(inputFeatures.get()) ?:
         parcel->writeInt32(displayId) ?:
         parcel->writeInt32(portalToDisplayId) ?:
         applicationInfo.writeToParcel(parcel) ?:
@@ -236,12 +124,15 @@
     }
 
     token = parcel->readStrongBinder();
-    dispatchingTimeout = decltype(dispatchingTimeout)(parcel->readInt64());
-    status_t status = parcel->readInt32(&id) ?:
-        parcel->readUtf8FromUtf16(&name) ?:
-        parcel->readInt32(&layoutParamsFlags) ?:
-        parcel->readInt32(&layoutParamsType) ?:
-        parcel->readInt32(&frameLeft) ?:
+    dispatchingTimeout = static_cast<decltype(dispatchingTimeout)>(parcel->readInt64());
+    status_t status = parcel->readInt32(&id) ?: parcel->readUtf8FromUtf16(&name);
+    if (status != OK) {
+        return status;
+    }
+
+    flags = Flags<Flag>(parcel->readInt32());
+    type = static_cast<Type>(parcel->readInt32());
+    status = parcel->readInt32(&frameLeft) ?:
         parcel->readInt32(&frameTop) ?:
         parcel->readInt32(&frameRight) ?:
         parcel->readInt32(&frameBottom) ?:
@@ -256,17 +147,26 @@
         parcel->readBool(&paused) ?:
         parcel->readBool(&trustedOverlay) ?:
         parcel->readInt32(&ownerPid) ?:
-        parcel->readInt32(&ownerUid) ?:
-        parcel->readInt32(&inputFeatures) ?:
-        parcel->readInt32(&displayId) ?:
+        parcel->readInt32(&ownerUid);
+
+    if (status != OK) {
+        return status;
+    }
+
+    inputFeatures = Flags<Feature>(parcel->readInt32());
+    status = parcel->readInt32(&displayId) ?:
         parcel->readInt32(&portalToDisplayId) ?:
         applicationInfo.readFromParcel(parcel) ?:
         parcel->read(touchableRegion) ?:
         parcel->readBool(&replaceTouchableRegionWithCrop);
 
+    if (status != OK) {
+        return status;
+    }
+
     touchableRegionCropHandle = parcel->readStrongBinder();
 
-    return status;
+    return OK;
 }
 
 // --- InputWindowHandle ---
@@ -299,4 +199,106 @@
     mInfo = handle->mInfo;
 }
 
+std::optional<std::string> InputWindowInfo::flagToString(Flag flag) {
+    switch (flag) {
+        case InputWindowInfo::Flag::ALLOW_LOCK_WHILE_SCREEN_ON: {
+            return "ALLOW_LOCK_WHILE_SCREEN_ON";
+        }
+        case InputWindowInfo::Flag::DIM_BEHIND: {
+            return "DIM_BEHIND";
+        }
+        case InputWindowInfo::Flag::BLUR_BEHIND: {
+            return "BLUR_BEHIND";
+        }
+        case InputWindowInfo::Flag::NOT_FOCUSABLE: {
+            return "NOT_FOCUSABLE";
+        }
+        case InputWindowInfo::Flag::NOT_TOUCHABLE: {
+            return "NOT_TOUCHABLE";
+        }
+        case InputWindowInfo::Flag::NOT_TOUCH_MODAL: {
+            return "NOT_TOUCH_MODAL";
+        }
+        case InputWindowInfo::Flag::TOUCHABLE_WHEN_WAKING: {
+            return "TOUCHABLE_WHEN_WAKING";
+        }
+        case InputWindowInfo::Flag::KEEP_SCREEN_ON: {
+            return "KEEP_SCREEN_ON";
+        }
+        case InputWindowInfo::Flag::LAYOUT_IN_SCREEN: {
+            return "LAYOUT_IN_SCREEN";
+        }
+        case InputWindowInfo::Flag::LAYOUT_NO_LIMITS: {
+            return "LAYOUT_NO_LIMITS";
+        }
+        case InputWindowInfo::Flag::FULLSCREEN: {
+            return "FULLSCREEN";
+        }
+        case InputWindowInfo::Flag::FORCE_NOT_FULLSCREEN: {
+            return "FORCE_NOT_FULLSCREEN";
+        }
+        case InputWindowInfo::Flag::DITHER: {
+            return "DITHER";
+        }
+        case InputWindowInfo::Flag::SECURE: {
+            return "SECURE";
+        }
+        case InputWindowInfo::Flag::SCALED: {
+            return "SCALED";
+        }
+        case InputWindowInfo::Flag::IGNORE_CHEEK_PRESSES: {
+            return "IGNORE_CHEEK_PRESSES";
+        }
+        case InputWindowInfo::Flag::LAYOUT_INSET_DECOR: {
+            return "LAYOUT_INSET_DECOR";
+        }
+        case InputWindowInfo::Flag::ALT_FOCUSABLE_IM: {
+            return "ALT_FOCUSABLE_IM";
+        }
+        case InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH: {
+            return "WATCH_OUTSIDE_TOUCH";
+        }
+        case InputWindowInfo::Flag::SHOW_WHEN_LOCKED: {
+            return "SHOW_WHEN_LOCKED";
+        }
+        case InputWindowInfo::Flag::SHOW_WALLPAPER: {
+            return "SHOW_WALLPAPER";
+        }
+        case InputWindowInfo::Flag::TURN_SCREEN_ON: {
+            return "TURN_SCREEN_ON";
+        }
+        case InputWindowInfo::Flag::DISMISS_KEYGUARD: {
+            return "DISMISS_KEYGUARD";
+        }
+        case InputWindowInfo::Flag::SPLIT_TOUCH: {
+            return "SPLIT_TOUCH";
+        }
+        case InputWindowInfo::Flag::HARDWARE_ACCELERATED: {
+            return "HARDWARE_ACCELERATED";
+        }
+        case InputWindowInfo::Flag::LAYOUT_IN_OVERSCAN: {
+            return "LAYOUT_IN_OVERSCAN";
+        }
+        case InputWindowInfo::Flag::TRANSLUCENT_STATUS: {
+            return "TRANSLUCENT_STATUS";
+        }
+        case InputWindowInfo::Flag::TRANSLUCENT_NAVIGATION: {
+            return "TRANSLUCENT_NAVIGATION";
+        }
+        case InputWindowInfo::Flag::LOCAL_FOCUS_MODE: {
+            return "LOCAL_FOCUS_MODE";
+        }
+        case InputWindowInfo::Flag::SLIPPERY: {
+            return "SLIPPERY";
+        }
+        case InputWindowInfo::Flag::LAYOUT_ATTACHED_IN_DECOR: {
+            return "LAYOUT_ATTACHED_IN_DECOR";
+        }
+        case InputWindowInfo::Flag::DRAWS_SYSTEM_BAR_BACKGROUNDS: {
+            return "DRAWS_SYSTEM_BAR_BACKGROUNDS";
+        }
+    }
+    return std::nullopt;
+}
+
 } // namespace android
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 3b57146..9782c1a 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -2,6 +2,7 @@
 cc_test {
     name: "libinput_tests",
     srcs: [
+        "Flags_test.cpp",
         "IdGenerator_test.cpp",
         "InputChannel_test.cpp",
         "InputDevice_test.cpp",
diff --git a/libs/input/tests/Flags_test.cpp b/libs/input/tests/Flags_test.cpp
new file mode 100644
index 0000000..800404d
--- /dev/null
+++ b/libs/input/tests/Flags_test.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright 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.
+ */
+
+#include <gtest/gtest.h>
+#include <input/Flags.h>
+
+#include <type_traits>
+
+namespace android::test {
+
+using namespace android::flag_operators;
+
+enum class TestFlags { ONE = 0x1, TWO = 0x2, THREE = 0x4 };
+
+static std::optional<std::string> toStringComplete(TestFlags f) {
+    switch (f) {
+        case TestFlags::ONE:
+            return "ONE";
+        case TestFlags::TWO:
+            return "TWO";
+        case TestFlags::THREE:
+            return "THREE";
+    }
+    return std::nullopt;
+}
+
+static std::optional<std::string> toStringIncomplete(TestFlags f) {
+    switch (f) {
+        case TestFlags::ONE:
+            return "ONE";
+        case TestFlags::TWO:
+            return "TWO";
+        case TestFlags::THREE:
+        default:
+            return std::nullopt;
+    }
+}
+
+TEST(Flags, Test) {
+    Flags<TestFlags> flags = TestFlags::ONE;
+    ASSERT_TRUE(flags.test(TestFlags::ONE));
+    ASSERT_FALSE(flags.test(TestFlags::TWO));
+    ASSERT_FALSE(flags.test(TestFlags::THREE));
+}
+
+TEST(Flags, Any) {
+    Flags<TestFlags> flags = TestFlags::ONE | TestFlags::TWO;
+    ASSERT_TRUE(flags.any(TestFlags::ONE));
+    ASSERT_TRUE(flags.any(TestFlags::TWO));
+    ASSERT_FALSE(flags.any(TestFlags::THREE));
+    ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO));
+    ASSERT_TRUE(flags.any(TestFlags::TWO | TestFlags::THREE));
+    ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::THREE));
+    ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE));
+}
+
+TEST(Flags, All) {
+    Flags<TestFlags> flags = TestFlags::ONE | TestFlags::TWO;
+    ASSERT_TRUE(flags.all(TestFlags::ONE));
+    ASSERT_TRUE(flags.all(TestFlags::TWO));
+    ASSERT_FALSE(flags.all(TestFlags::THREE));
+    ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO));
+    ASSERT_FALSE(flags.all(TestFlags::TWO | TestFlags::THREE));
+    ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::THREE));
+    ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE));
+}
+
+TEST(Flags, DefaultConstructor_hasNoFlagsSet) {
+    Flags<TestFlags> flags;
+    ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE));
+}
+
+TEST(Flags, NotOperator_onEmptyFlagsSetsAllFlags) {
+    Flags<TestFlags> flags;
+    flags = ~flags;
+    ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE));
+}
+
+TEST(Flags, NotOperator_onNonEmptyFlagsInvertsFlags) {
+    Flags<TestFlags> flags = TestFlags::TWO;
+    flags = ~flags;
+    ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE));
+    ASSERT_FALSE(flags.test(TestFlags::TWO));
+}
+
+TEST(Flags, OrOperator_withNewFlag) {
+    Flags<TestFlags> flags = TestFlags::ONE;
+    Flags<TestFlags> flags2 = flags | TestFlags::TWO;
+    ASSERT_FALSE(flags2.test(TestFlags::THREE));
+    ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::TWO));
+}
+
+TEST(Flags, OrOperator_withExistingFlag) {
+    Flags<TestFlags> flags = TestFlags::ONE | TestFlags::THREE;
+    Flags<TestFlags> flags2 = flags | TestFlags::THREE;
+    ASSERT_FALSE(flags2.test(TestFlags::TWO));
+    ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::THREE));
+}
+
+TEST(Flags, OrEqualsOperator_withNewFlag) {
+    Flags<TestFlags> flags;
+    flags |= TestFlags::THREE;
+    ASSERT_TRUE(flags.test(TestFlags::THREE));
+    ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO));
+}
+
+TEST(Flags, OrEqualsOperator_withExistingFlag) {
+    Flags<TestFlags> flags = TestFlags::ONE | TestFlags::THREE;
+    flags |= TestFlags::THREE;
+    ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE));
+    ASSERT_FALSE(flags.test(TestFlags::TWO));
+}
+
+TEST(Flags, AndOperator_withOneSetFlag) {
+    Flags<TestFlags> flags = TestFlags::ONE | TestFlags::THREE;
+    Flags<TestFlags> andFlags = flags & TestFlags::THREE;
+    ASSERT_TRUE(andFlags.test(TestFlags::THREE));
+    ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO));
+}
+
+TEST(Flags, AndOperator_withMultipleSetFlags) {
+    Flags<TestFlags> flags = TestFlags::ONE | TestFlags::THREE;
+    Flags<TestFlags> andFlags = flags & (TestFlags::ONE | TestFlags::THREE);
+    ASSERT_TRUE(andFlags.all(TestFlags::ONE | TestFlags::THREE));
+    ASSERT_FALSE(andFlags.test(TestFlags::TWO));
+}
+
+TEST(Flags, AndOperator_withNoSetFlags) {
+    Flags<TestFlags> flags = TestFlags::ONE | TestFlags::THREE;
+    Flags<TestFlags> andFlags = flags & TestFlags::TWO;
+    ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE));
+}
+
+TEST(Flags, Equality) {
+    Flags<TestFlags> flags1 = TestFlags::ONE | TestFlags::TWO;
+    Flags<TestFlags> flags2 = TestFlags::ONE | TestFlags::TWO;
+    ASSERT_EQ(flags1, flags2);
+}
+
+TEST(Flags, Inequality) {
+    Flags<TestFlags> flags1 = TestFlags::ONE | TestFlags::TWO;
+    Flags<TestFlags> flags2 = TestFlags::ONE | TestFlags::THREE;
+    ASSERT_NE(flags1, flags2);
+}
+
+TEST(Flags, EqualsOperator) {
+    Flags<TestFlags> flags;
+    flags = TestFlags::ONE;
+    ASSERT_TRUE(flags.test(TestFlags::ONE));
+    ASSERT_FALSE(flags.any(TestFlags::TWO | TestFlags::THREE));
+}
+
+TEST(Flags, EqualsOperator_DontShareState) {
+    Flags<TestFlags> flags1 = TestFlags::ONE | TestFlags::TWO;
+    Flags<TestFlags> flags2 = flags1;
+    ASSERT_EQ(flags1, flags2);
+
+    flags1 &= TestFlags::TWO;
+    ASSERT_NE(flags1, flags2);
+}
+
+TEST(Flags, String_NoFlagsWithDefaultStringify) {
+    Flags<TestFlags> flags;
+    ASSERT_EQ(flags.string(), "0x0");
+}
+
+TEST(Flags, String_NoFlagsWithNonDefaultStringify) {
+    Flags<TestFlags> flags;
+    ASSERT_EQ(flags.string(toStringComplete), "0x0");
+}
+
+TEST(Flags, String_WithDefaultStringify) {
+    Flags<TestFlags> flags = TestFlags::ONE | TestFlags::TWO;
+    ASSERT_EQ(flags.string(), "0x00000003");
+}
+
+TEST(Flags, String_WithCompleteStringify) {
+    Flags<TestFlags> flags = TestFlags::ONE | TestFlags::TWO;
+    ASSERT_EQ(flags.string(toStringComplete), "ONE | TWO");
+}
+
+TEST(Flags, String_WithIncompleteStringify) {
+    Flags<TestFlags> flags = TestFlags::ONE | TestFlags::THREE;
+    ASSERT_EQ(flags.string(toStringIncomplete), "ONE | 0x00000004");
+}
+
+} // namespace android::test
\ No newline at end of file
diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp
index cdea922..e7a4587 100644
--- a/libs/input/tests/InputWindow_test.cpp
+++ b/libs/input/tests/InputWindow_test.cpp
@@ -44,8 +44,8 @@
     i.token = new BBinder();
     i.id = 1;
     i.name = "Foobar";
-    i.layoutParamsFlags = 7;
-    i.layoutParamsType = 39;
+    i.flags = InputWindowInfo::Flag::SLIPPERY;
+    i.type = InputWindowInfo::Type::INPUT_METHOD;
     i.dispatchingTimeout = 12s;
     i.frameLeft = 93;
     i.frameTop = 34;
@@ -62,7 +62,7 @@
     i.paused = false;
     i.ownerPid = 19;
     i.ownerUid = 24;
-    i.inputFeatures = 29;
+    i.inputFeatures = InputWindowInfo::Feature::DISABLE_USER_ACTIVITY;
     i.displayId = 34;
     i.portalToDisplayId = 2;
     i.replaceTouchableRegionWithCrop = true;
@@ -76,8 +76,8 @@
     ASSERT_EQ(i.token, i2.token);
     ASSERT_EQ(i.id, i2.id);
     ASSERT_EQ(i.name, i2.name);
-    ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags);
-    ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType);
+    ASSERT_EQ(i.flags, i2.flags);
+    ASSERT_EQ(i.type, i2.type);
     ASSERT_EQ(i.dispatchingTimeout, i2.dispatchingTimeout);
     ASSERT_EQ(i.frameLeft, i2.frameLeft);
     ASSERT_EQ(i.frameTop, i2.frameTop);
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 7d8ab75..a15b7b2 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -157,8 +157,7 @@
     virtual bool updateInfo() override {
         mInfo.token = mServerChannel->getConnectionToken();
         mInfo.name = "FakeWindowHandle";
-        mInfo.layoutParamsFlags = 0;
-        mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
+        mInfo.type = InputWindowInfo::Type::APPLICATION;
         mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
         mInfo.frameLeft = mFrame.left;
         mInfo.frameTop = mFrame.top;
@@ -174,7 +173,6 @@
         mInfo.paused = false;
         mInfo.ownerPid = INJECTOR_PID;
         mInfo.ownerUid = INJECTOR_UID;
-        mInfo.inputFeatures = 0;
         mInfo.displayId = ADISPLAY_ID_DEFAULT;
 
         return true;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 5df4aec..36bbc6d 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -45,28 +45,29 @@
 
 #include "InputDispatcher.h"
 
-#include "Connection.h"
-
-#include <errno.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <statslog.h>
-#include <stddef.h>
-#include <time.h>
-#include <unistd.h>
-#include <queue>
-#include <sstream>
-
 #include <android-base/chrono_utils.h>
 #include <android-base/stringprintf.h>
 #include <binder/Binder.h>
 #include <input/InputDevice.h>
+#include <input/InputWindow.h>
 #include <log/log.h>
 #include <openssl/hmac.h>
 #include <openssl/rand.h>
 #include <powermanager/PowerManager.h>
+#include <statslog.h>
+#include <unistd.h>
 #include <utils/Trace.h>
 
+#include <cerrno>
+#include <cinttypes>
+#include <climits>
+#include <cstddef>
+#include <ctime>
+#include <queue>
+#include <sstream>
+
+#include "Connection.h"
+
 #define INDENT "  "
 #define INDENT2 "    "
 #define INDENT3 "      "
@@ -816,13 +817,12 @@
     for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
         const InputWindowInfo* windowInfo = windowHandle->getInfo();
         if (windowInfo->displayId == displayId) {
-            int32_t flags = windowInfo->layoutParamsFlags;
+            auto flags = windowInfo->flags;
 
             if (windowInfo->visible) {
-                if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
-                    bool isTouchModal = (flags &
-                                         (InputWindowInfo::FLAG_NOT_FOCUSABLE |
-                                          InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
+                if (!flags.test(InputWindowInfo::Flag::NOT_TOUCHABLE)) {
+                    bool isTouchModal = !flags.test(InputWindowInfo::Flag::NOT_FOCUSABLE) &&
+                            !flags.test(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
                     if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
                         int32_t portalToDisplayId = windowInfo->portalToDisplayId;
                         if (portalToDisplayId != ADISPLAY_ID_NONE &&
@@ -839,7 +839,7 @@
                     }
                 }
 
-                if (addOutsideTargets && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
+                if (addOutsideTargets && flags.test(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
                     touchState->addOrUpdateWindow(windowHandle,
                                                   InputTarget::FLAG_DISPATCH_AS_OUTSIDE,
                                                   BitSet32(0));
@@ -1888,7 +1888,7 @@
             for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
                 const InputWindowInfo* info = windowHandle->getInfo();
                 if (info->displayId == displayId &&
-                    windowHandle->getInfo()->layoutParamsType == InputWindowInfo::TYPE_WALLPAPER) {
+                    windowHandle->getInfo()->type == InputWindowInfo::Type::WALLPAPER) {
                     tempTouchState
                             .addOrUpdateWindow(windowHandle,
                                                InputTarget::FLAG_WINDOW_IS_OBSCURED |
@@ -2170,7 +2170,7 @@
             getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
     if (focusedWindowHandle != nullptr) {
         const InputWindowInfo* info = focusedWindowHandle->getInfo();
-        if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) {
+        if (info->inputFeatures.test(InputWindowInfo::Feature::DISABLE_USER_ACTIVITY)) {
 #if DEBUG_DISPATCH_CYCLE
             ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str());
 #endif
@@ -3647,10 +3647,9 @@
         if ((getInputChannelLocked(handle->getToken()) == nullptr &&
              info->portalToDisplayId == ADISPLAY_ID_NONE)) {
             const bool noInputChannel =
-                    info->inputFeatures & InputWindowInfo::INPUT_FEATURE_NO_INPUT_CHANNEL;
-            const bool canReceiveInput =
-                    !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_TOUCHABLE) ||
-                    !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_FOCUSABLE);
+                    info->inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL);
+            const bool canReceiveInput = !info->flags.test(InputWindowInfo::Flag::NOT_TOUCHABLE) ||
+                    !info->flags.test(InputWindowInfo::Flag::NOT_FOCUSABLE);
             if (canReceiveInput && !noInputChannel) {
                 ALOGV("Window handle %s has no registered input channel",
                       handle->getName().c_str());
@@ -4140,7 +4139,7 @@
                     dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, "
                                                  "portalToDisplayId=%d, paused=%s, hasFocus=%s, "
                                                  "hasWallpaper=%s, visible=%s, canReceiveKeys=%s, "
-                                                 "flags=0x%08x, type=0x%08x, "
+                                                 "flags=%s, type=0x%08x, "
                                                  "frame=[%d,%d][%d,%d], globalScale=%f, "
                                                  "windowScale=(%f,%f), touchableRegion=",
                                          i, windowInfo->name.c_str(), windowInfo->displayId,
@@ -4150,20 +4149,20 @@
                                          toString(windowInfo->hasWallpaper),
                                          toString(windowInfo->visible),
                                          toString(windowInfo->canReceiveKeys),
-                                         windowInfo->layoutParamsFlags,
-                                         windowInfo->layoutParamsType, windowInfo->frameLeft,
-                                         windowInfo->frameTop, windowInfo->frameRight,
-                                         windowInfo->frameBottom, windowInfo->globalScaleFactor,
-                                         windowInfo->windowXScale, windowInfo->windowYScale);
+                                         windowInfo->flags.string(InputWindowInfo::flagToString)
+                                                 .c_str(),
+                                         static_cast<int32_t>(windowInfo->type),
+                                         windowInfo->frameLeft, windowInfo->frameTop,
+                                         windowInfo->frameRight, windowInfo->frameBottom,
+                                         windowInfo->globalScaleFactor, windowInfo->windowXScale,
+                                         windowInfo->windowYScale);
                     dumpRegion(dump, windowInfo->touchableRegion);
-                    dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
+                    dump += StringPrintf(", inputFeatures=%s",
+                                         windowInfo->inputFeatures.string().c_str());
                     dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64
                                          "ms\n",
                                          windowInfo->ownerPid, windowInfo->ownerUid,
                                          millis(windowInfo->dispatchingTimeout));
-                    dump += StringPrintf(INDENT4 "    flags: %s\n",
-                                         inputWindowFlagsToString(windowInfo->layoutParamsFlags)
-                                                 .c_str());
                 }
             } else {
                 dump += INDENT2 "Windows: <none>\n";
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index 2baceba..81b3cf0 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -137,8 +137,7 @@
     for (const TouchedWindow& window : windows) {
         if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
             if (haveSlipperyForegroundWindow ||
-                !(window.windowHandle->getInfo()->layoutParamsFlags &
-                  InputWindowInfo::FLAG_SLIPPERY)) {
+                !window.windowHandle->getInfo()->flags.test(InputWindowInfo::Flag::SLIPPERY)) {
                 return false;
             }
             haveSlipperyForegroundWindow = true;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 86b4868..c749806 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -29,6 +29,7 @@
 #include <vector>
 
 using android::base::StringPrintf;
+using namespace android::flag_operators;
 
 namespace android::inputdispatcher {
 
@@ -766,8 +767,7 @@
         mInfo.token = token;
         mInfo.id = sId++;
         mInfo.name = name;
-        mInfo.layoutParamsFlags = 0;
-        mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
+        mInfo.type = InputWindowInfo::Type::APPLICATION;
         mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
         mInfo.frameLeft = 0;
         mInfo.frameTop = 0;
@@ -783,7 +783,6 @@
         mInfo.paused = false;
         mInfo.ownerPid = INJECTOR_PID;
         mInfo.ownerUid = INJECTOR_UID;
-        mInfo.inputFeatures = 0;
         mInfo.displayId = displayId;
     }
 
@@ -806,7 +805,7 @@
         mInfo.addTouchableRegion(frame);
     }
 
-    void setLayoutParamFlags(int32_t flags) { mInfo.layoutParamsFlags = flags; }
+    void setFlags(Flags<InputWindowInfo::Flag> flags) { mInfo.flags = flags; }
 
     void setWindowScale(float xScale, float yScale) {
         mInfo.windowXScale = xScale;
@@ -1165,7 +1164,7 @@
     sp<FakeWindowHandle> window =
             new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
     window->setFrame(Rect(0, 0, 100, 100));
-    window->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+    window->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
@@ -1188,7 +1187,7 @@
     sp<FakeWindowHandle> window =
             new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
     window->setFrame(Rect(0, 0, 100, 100));
-    window->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+    window->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -1298,11 +1297,11 @@
     sp<FakeWindowHandle> windowLeft =
             new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
     windowLeft->setFrame(Rect(0, 0, 600, 800));
-    windowLeft->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+    windowLeft->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
     sp<FakeWindowHandle> windowRight =
             new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
     windowRight->setFrame(Rect(600, 0, 1200, 800));
-    windowRight->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+    windowRight->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
@@ -1409,7 +1408,7 @@
     sp<FakeWindowHandle> window =
             new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
     window->setFrame(Rect(0, 0, 1200, 800));
-    window->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+    window->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
@@ -1491,11 +1490,11 @@
     sp<FakeWindowHandle> windowLeft =
             new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
     windowLeft->setFrame(Rect(0, 0, 600, 800));
-    windowLeft->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+    windowLeft->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
     sp<FakeWindowHandle> windowRight =
             new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
     windowRight->setFrame(Rect(600, 0, 1200, 800));
-    windowRight->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+    windowRight->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
 
     mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
 
@@ -1654,15 +1653,15 @@
     sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher,
             "First Window", ADISPLAY_ID_DEFAULT);
     firstWindow->setFrame(Rect(0, 0, 600, 400));
-    firstWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL
-            | InputWindowInfo::FLAG_SPLIT_TOUCH);
+    firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
+                          InputWindowInfo::Flag::SPLIT_TOUCH);
 
     // Create a non touch modal window that supports split touch
     sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher,
             "Second Window", ADISPLAY_ID_DEFAULT);
     secondWindow->setFrame(Rect(0, 400, 600, 800));
-    secondWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL
-            | InputWindowInfo::FLAG_SPLIT_TOUCH);
+    secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
+                           InputWindowInfo::Flag::SPLIT_TOUCH);
 
     // Add the windows to the dispatcher
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2347,12 +2346,12 @@
         mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
         // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
         // window.
-        mUnfocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+        mUnfocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
 
         mFocusedWindow =
                 new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
         mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
-        mFocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+        mFocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
 
         // Set focused application.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -2440,14 +2439,14 @@
                                         ADISPLAY_ID_DEFAULT);
         // Adding FLAG_NOT_TOUCH_MODAL otherwise all taps will go to the top most window.
         // We also need FLAG_SPLIT_TOUCH or we won't be able to get touches for both windows.
-        mWindow1->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL |
-                                      InputWindowInfo::FLAG_SPLIT_TOUCH);
+        mWindow1->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
+                           InputWindowInfo::Flag::SPLIT_TOUCH);
         mWindow1->setFrame(Rect(0, 0, 100, 100));
 
         mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2",
                                         ADISPLAY_ID_DEFAULT, mWindow1->getToken());
-        mWindow2->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL |
-                                      InputWindowInfo::FLAG_SPLIT_TOUCH);
+        mWindow2->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
+                           InputWindowInfo::Flag::SPLIT_TOUCH);
         mWindow2->setFrame(Rect(100, 100, 200, 200));
 
         mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}});
@@ -2671,7 +2670,7 @@
         mWindow->setFocus(true);
         // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
         // window.
-        mWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+        mWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
 
         // Set focused application.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
@@ -3053,16 +3052,16 @@
         // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
         // window.
         // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
-        mUnfocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL |
-                                              InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH |
-                                              InputWindowInfo::FLAG_SPLIT_TOUCH);
+        mUnfocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
+                                   InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH |
+                                   InputWindowInfo::Flag::SPLIT_TOUCH);
 
         mFocusedWindow =
                 new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT);
         mFocusedWindow->setDispatchingTimeout(30ms);
         mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
-        mFocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL |
-                                            InputWindowInfo::FLAG_SPLIT_TOUCH);
+        mFocusedWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
+                                 InputWindowInfo::Flag::SPLIT_TOUCH);
 
         // Set focused application.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication);
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
index 6d50519..193fe77 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -57,8 +57,8 @@
 static const sp<IBinder> TestInfoToken = new BBinder();
 static constexpr int32_t TestInfoId = 1;
 static const std::string TestInfoName = "InputFlingerServiceTestInputWindowInfo";
-static constexpr int32_t TestInfoLayoutParamsFlags = 0xABCD;
-static constexpr int32_t TestInfoLayoutParamsType = 39;
+static constexpr Flags<InputWindowInfo::Flag> TestInfoFlags = InputWindowInfo::Flag::NOT_FOCUSABLE;
+static constexpr InputWindowInfo::Type TestInfoType = InputWindowInfo::Type::INPUT_METHOD;
 static constexpr std::chrono::duration TestInfoDispatchingTimeout = 2532ms;
 static constexpr int32_t TestInfoFrameLeft = 93;
 static constexpr int32_t TestInfoFrameTop = 34;
@@ -79,7 +79,8 @@
 static constexpr bool TestInfoPaused = false;
 static constexpr int32_t TestInfoOwnerPid = 19;
 static constexpr int32_t TestInfoOwnerUid = 24;
-static constexpr int32_t TestInfoInputFeatures = 29;
+static constexpr InputWindowInfo::Feature TestInfoInputFeatures =
+        InputWindowInfo::Feature::NO_INPUT_CHANNEL;
 static constexpr int32_t TestInfoDisplayId = 34;
 static constexpr int32_t TestInfoPortalToDisplayId = 2;
 static constexpr bool TestInfoReplaceTouchableRegionWithCrop = true;
@@ -265,8 +266,8 @@
     mInfo.token = TestInfoToken;
     mInfo.id = TestInfoId;
     mInfo.name = TestInfoName;
-    mInfo.layoutParamsFlags = TestInfoLayoutParamsFlags;
-    mInfo.layoutParamsType = TestInfoLayoutParamsType;
+    mInfo.flags = TestInfoFlags;
+    mInfo.type = TestInfoType;
     mInfo.dispatchingTimeout = TestInfoDispatchingTimeout;
     mInfo.frameLeft = TestInfoFrameLeft;
     mInfo.frameTop = TestInfoFrameTop;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 67becab..70822bd 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -67,12 +67,14 @@
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
 #include "TimeStats/TimeStats.h"
+#include "input/InputWindow.h"
 
 #define DEBUG_RESIZE 0
 
 namespace android {
 
 using base::StringAppendF;
+using namespace android::flag_operators;
 
 std::atomic<int32_t> Layer::sSequence{1};
 
@@ -80,7 +82,8 @@
       : mFlinger(args.flinger),
         mName(args.name),
         mClientRef(args.client),
-        mWindowType(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0)) {
+        mWindowType(static_cast<InputWindowInfo::Type>(
+                args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))) {
     uint32_t layerFlags = 0;
     if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
     if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
@@ -2371,9 +2374,8 @@
         mDrawingState.inputInfo.name = getName();
         mDrawingState.inputInfo.ownerUid = mCallingUid;
         mDrawingState.inputInfo.ownerPid = mCallingPid;
-        mDrawingState.inputInfo.inputFeatures =
-            InputWindowInfo::INPUT_FEATURE_NO_INPUT_CHANNEL;
-        mDrawingState.inputInfo.layoutParamsFlags = InputWindowInfo::FLAG_NOT_TOUCH_MODAL;
+        mDrawingState.inputInfo.inputFeatures = InputWindowInfo::Feature::NO_INPUT_CHANNEL;
+        mDrawingState.inputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL;
         mDrawingState.inputInfo.displayId = getLayerStack();
     }
 
@@ -2575,7 +2577,7 @@
     }
     // Cloned layers shouldn't handle watch outside since their z order is not determined by
     // WM or the client.
-    mDrawingState.inputInfo.layoutParamsFlags &= ~InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH;
+    mDrawingState.inputInfo.flags &= ~InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH;
 }
 
 void Layer::updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6bcbfca..99b1bb1 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -286,7 +286,7 @@
 
     void onFirstRef() override;
 
-    int getWindowType() const { return mWindowType; }
+    InputWindowInfo::Type getWindowType() const { return mWindowType; }
 
     void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; }
     bool getPrimaryDisplayOnly() const { return mPrimaryDisplayOnly; }
@@ -1038,7 +1038,7 @@
     bool mChildrenChanged{false};
 
     // Window types from WindowManager.LayoutParams
-    const int mWindowType;
+    const InputWindowInfo::Type mWindowType;
 
 private:
     virtual void setTransformHint(ui::Transform::RotationFlags) {}
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 0fe1421..dd65cf4 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -131,8 +131,12 @@
     }
 
     InputWindowInfoProto* proto = getInputWindowInfoProto();
-    proto->set_layout_params_flags(inputInfo.layoutParamsFlags);
-    proto->set_layout_params_type(inputInfo.layoutParamsType);
+    proto->set_layout_params_flags(inputInfo.flags.get());
+    using U = std::underlying_type_t<InputWindowInfo::Type>;
+    // TODO(b/129481165): This static assert can be safely removed once conversion warnings
+    // are re-enabled.
+    static_assert(std::is_same_v<U, int32_t>);
+    proto->set_layout_params_type(static_cast<U>(inputInfo.type));
 
     LayerProtoHelper::writeToProto({inputInfo.frameLeft, inputInfo.frameTop, inputInfo.frameRight,
                                     inputInfo.frameBottom},
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index ab63d64..8dd4b0a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -432,7 +432,7 @@
     const auto minFps = mRefreshRateConfigs.getMinRefreshRate().getFps();
     const auto maxFps = mRefreshRateConfigs.getMaxRefreshRate().getFps();
 
-    if (layer->getWindowType() == InputWindowInfo::TYPE_STATUS_BAR) {
+    if (layer->getWindowType() == InputWindowInfo::Type::STATUS_BAR) {
         mLayerHistory->registerLayer(layer, minFps, maxFps,
                                      scheduler::LayerHistory::LayerVoteType::NoVote);
     } else if (!mUseContentDetection) {
@@ -445,12 +445,12 @@
         // In V1 of content detection, all layers are registered as Heuristic (unless it's
         // wallpaper).
         const auto highFps =
-                layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER ? minFps : maxFps;
+                layer->getWindowType() == InputWindowInfo::Type::WALLPAPER ? minFps : maxFps;
 
         mLayerHistory->registerLayer(layer, minFps, highFps,
                                      scheduler::LayerHistory::LayerVoteType::Heuristic);
     } else {
-        if (layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER) {
+        if (layer->getWindowType() == InputWindowInfo::Type::WALLPAPER) {
             // Running Wallpaper at Min is considered as part of content detection.
             mLayerHistory->registerLayer(layer, minFps, maxFps,
                                          scheduler::LayerHistory::LayerVoteType::Min);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index aa7b903..93bc11a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -90,6 +90,7 @@
 #include <functional>
 #include <mutex>
 #include <optional>
+#include <type_traits>
 #include <unordered_map>
 
 #include "BufferLayer.h"
@@ -3981,7 +3982,12 @@
     if (metadata.has(METADATA_WINDOW_TYPE)) {
         int32_t windowType = metadata.getInt32(METADATA_WINDOW_TYPE, 0);
         if (windowType == 441731) {
-            metadata.setInt32(METADATA_WINDOW_TYPE, InputWindowInfo::TYPE_NAVIGATION_BAR_PANEL);
+            using U = std::underlying_type_t<InputWindowInfo::Type>;
+            // TODO(b/129481165): This static assert can be safely removed once conversion warnings
+            // are re-enabled.
+            static_assert(std::is_same_v<U, int32_t>);
+            metadata.setInt32(METADATA_WINDOW_TYPE,
+                              static_cast<U>(InputWindowInfo::Type::NAVIGATION_BAR_PANEL));
             primaryDisplayOnly = true;
         }
     }