2/ Move device state logic to its own class

- Feed the class down to the input consumers and related gesture classes
  instead of specific sysui state flags

Bug: 141886704

Change-Id: I2ade7f48555c9d0ba0d3fac5c1f2dae694624224
diff --git a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 19dd82f..6b936cb 100644
--- a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -34,6 +34,8 @@
 
 import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.DefaultDisplay;
+import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 
@@ -44,15 +46,6 @@
 public class TouchInteractionService extends Service {
 
     private static final String TAG = "GoTouchInteractionService";
-    private boolean mIsUserUnlocked;
-    private BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
-                initWhenUserUnlocked();
-            }
-        }
-    };
 
     private final IBinder mMyBinder = new IOverviewProxy.Stub() {
 
@@ -68,21 +61,21 @@
 
         @Override
         public void onOverviewToggle() {
-            if (mIsUserUnlocked) {
+            if (mDeviceState.isUserUnlocked()) {
                 mOverviewCommandHelper.onOverviewToggle();
             }
         }
 
         @Override
         public void onOverviewShown(boolean triggeredFromAltTab) {
-            if (mIsUserUnlocked) {
+            if (mDeviceState.isUserUnlocked()) {
                 mOverviewCommandHelper.onOverviewShown(triggeredFromAltTab);
             }
         }
 
         @Override
         public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
-            if (mIsUserUnlocked && triggeredFromAltTab && !triggeredFromHomeKey) {
+            if (mDeviceState.isUserUnlocked() && triggeredFromAltTab && !triggeredFromHomeKey) {
                 // onOverviewShownFromAltTab hides the overview and ends at the target app
                 mOverviewCommandHelper.onOverviewHidden();
             }
@@ -90,7 +83,7 @@
 
         @Override
         public void onTip(int actionType, int viewType) {
-            if (mIsUserUnlocked) {
+            if (mDeviceState.isUserUnlocked()) {
                 mOverviewCommandHelper.onTip(actionType, viewType);
             }
         }
@@ -140,35 +133,30 @@
     private RecentsModel mRecentsModel;
     private OverviewComponentObserver mOverviewComponentObserver;
     private OverviewCommandHelper mOverviewCommandHelper;
+    private RecentsAnimationDeviceState mDeviceState;
 
     @Override
     public void onCreate() {
         super.onCreate();
-        if (UserManagerCompat.getInstance(this).isUserUnlocked(Process.myUserHandle())) {
-            initWhenUserUnlocked();
-        } else {
-            mIsUserUnlocked = false;
-            registerReceiver(mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
-        }
+        mDeviceState = new RecentsAnimationDeviceState(this);
+        mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
 
         sConnected = true;
     }
 
-    private void initWhenUserUnlocked() {
+    public void onUserUnlocked() {
         mRecentsModel = RecentsModel.INSTANCE.get(this);
-        mOverviewComponentObserver = new OverviewComponentObserver(this);
+        mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
         mOverviewCommandHelper = new OverviewCommandHelper(this,
                 mOverviewComponentObserver);
-        mIsUserUnlocked = true;
-        Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver);
     }
 
     @Override
     public void onDestroy() {
-        if (mIsUserUnlocked) {
+        if (mDeviceState.isUserUnlocked()) {
             mOverviewComponentObserver.onDestroy();
         }
-        Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver);
+        mDeviceState.destroy();
         sConnected = false;
         super.onDestroy();
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index bb73521..c749761 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -38,7 +38,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.graphics.Region;
 import android.os.UserHandle;
 import android.view.MotionEvent;
 import android.view.View;
@@ -441,8 +440,8 @@
     }
 
     @Override
-    public boolean deferStartingActivity(Region activeNavBarRegion, MotionEvent ev) {
-        return activeNavBarRegion.contains((int) ev.getX(), (int) ev.getY());
+    public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
+        return deviceState.isInDeferredGestureRegion(ev);
     }
 
     @Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
index c4f375a..6ac7546 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -5,10 +5,12 @@
 import android.content.Context;
 import android.os.Bundle;
 
+import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.testing.TestInformationHandler;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.uioverrides.states.OverviewState;
 import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
+import com.android.launcher3.util.DefaultDisplay;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.RecentsView;
 
@@ -78,7 +80,8 @@
     }
 
     private RecentsView getRecentsView() {
-        OverviewComponentObserver observer = new OverviewComponentObserver(mContext);
+        OverviewComponentObserver observer = new OverviewComponentObserver(mContext,
+                new RecentsAnimationDeviceState(mContext));
         try {
             return observer.getActivityControlHelper().getCreatedActivity().getOverviewPanel();
         } finally {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 3b48fa7..4ca8055 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -27,15 +27,6 @@
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT;
 
 import android.annotation.TargetApi;
@@ -43,44 +34,31 @@
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.Service;
 import android.app.TaskInfo;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.res.Configuration;
-import android.graphics.Point;
-import android.graphics.RectF;
 import android.graphics.Region;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Looper;
-import android.os.Process;
 import android.os.RemoteException;
-import android.text.TextUtils;
 import android.util.Log;
 import android.view.Choreographer;
 import android.view.InputEvent;
 import android.view.MotionEvent;
-import android.view.Surface;
 
-import androidx.annotation.BinderThread;
 import androidx.annotation.UiThread;
 import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.BaseDraggingActivity;
-import com.android.launcher3.R;
-import com.android.launcher3.ResourceUtils;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.logging.EventLogArray;
 import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.model.AppLaunchTracker;
 import com.android.launcher3.provider.RestoreDbTask;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.uioverrides.DejankBinderTracker;
-import com.android.launcher3.util.DefaultDisplay;
 import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
 import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
@@ -99,10 +77,7 @@
 import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.InputMonitorCompat;
-import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
 import com.android.systemui.shared.system.RecentsAnimationListener;
-import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
 import com.android.systemui.shared.system.TaskInfoCompat;
 
 import java.io.FileDescriptor;
@@ -133,7 +108,7 @@
  */
 @TargetApi(Build.VERSION_CODES.Q)
 public class TouchInteractionService extends Service implements
-        NavigationModeChangeListener, DefaultDisplay.DisplayInfoChangeListener {
+        NavigationModeChangeListener {
 
     /**
      * NOTE: This value should be kept same as
@@ -154,10 +129,6 @@
 
     private final IBinder mMyBinder = new IOverviewProxy.Stub() {
 
-        public void onActiveNavBarRegionChanges(Region region) {
-            mActiveNavBarRegion = region;
-        }
-
         public void onInitialize(Bundle bundle) {
             mISystemUiProxy = ISystemUiProxy.Stub
                     .asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
@@ -192,14 +163,14 @@
 
         @Override
         public void onAssistantAvailable(boolean available) {
-            mAssistantAvailable = available;
+            MAIN_EXECUTOR.execute(() -> mDeviceState.setAssistantAvailable(available));
+            MAIN_EXECUTOR.execute(TouchInteractionService.this::onAssistantVisibilityChanged);
         }
 
         @Override
         public void onAssistantVisibilityChanged(float visibility) {
-            mLastAssistantVisibility = visibility;
-            MAIN_EXECUTOR.execute(
-                    TouchInteractionService.this::onAssistantVisibilityChanged);
+            MAIN_EXECUTOR.execute(() -> mDeviceState.setAssistantVisibility(visibility));
+            MAIN_EXECUTOR.execute(TouchInteractionService.this::onAssistantVisibilityChanged);
         }
 
         public void onBackAction(boolean completed, int downX, int downY, boolean isButton,
@@ -219,10 +190,14 @@
         }
 
         public void onSystemUiStateChanged(int stateFlags) {
-            mSystemUiStateFlags = stateFlags;
+            MAIN_EXECUTOR.execute(() -> mDeviceState.setSystemUiFlags(stateFlags));
             MAIN_EXECUTOR.execute(TouchInteractionService.this::onSystemUiFlagsChanged);
         }
 
+        public void onActiveNavBarRegionChanges(Region region) {
+            MAIN_EXECUTOR.execute(() -> mDeviceState.setDeferredGestureRegion(region));
+        }
+
         /** Deprecated methods **/
         public void onQuickStep(MotionEvent motionEvent) { }
 
@@ -272,71 +247,28 @@
     private OverviewCommandHelper mOverviewCommandHelper;
     private OverviewComponentObserver mOverviewComponentObserver;
     private OverviewInteractionState mOverviewInteractionState;
-    private TaskOverlayFactory mTaskOverlayFactory;
     private InputConsumerController mInputConsumer;
-    private boolean mAssistantAvailable;
-    private float mLastAssistantVisibility = 0;
-    private @SystemUiStateFlags int mSystemUiStateFlags;
-
-    private boolean mIsUserUnlocked;
-    private BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
-                initWhenUserUnlocked();
-            }
-        }
-    };
+    private RecentsAnimationDeviceState mDeviceState;
 
     private InputConsumer mUncheckedConsumer = InputConsumer.NO_OP;
     private InputConsumer mConsumer = InputConsumer.NO_OP;
     private Choreographer mMainChoreographer;
 
-    private Region mActiveNavBarRegion = new Region();
-
     private InputMonitorCompat mInputMonitorCompat;
     private InputEventReceiver mInputEventReceiver;
     private Mode mMode = Mode.THREE_BUTTONS;
-    private int mDefaultDisplayId;
-    private final RectF mSwipeTouchRegion = new RectF();
-    private final RectF mAssistantLeftRegion = new RectF();
-    private final RectF mAssistantRightRegion = new RectF();
-
-    private ComponentName mGestureBlockingActivity;
-
-    private Region mExclusionRegion;
-    private SystemGestureExclusionListenerCompat mExclusionListener;
 
     @Override
     public void onCreate() {
         super.onCreate();
+        mDeviceState = new RecentsAnimationDeviceState(this);
+        mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
 
         // Initialize anything here that is needed in direct boot mode.
-        // Everything else should be initialized in initWhenUserUnlocked() below.
+        // Everything else should be initialized in onUserUnlocked() below.
         mMainChoreographer = Choreographer.getInstance();
         mAM = ActivityManagerWrapper.getInstance();
 
-        if (UserManagerCompat.getInstance(this).isUserUnlocked(Process.myUserHandle())) {
-            initWhenUserUnlocked();
-        } else {
-            mIsUserUnlocked = false;
-            registerReceiver(mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
-        }
-
-        mDefaultDisplayId = DefaultDisplay.INSTANCE.get(this).getInfo().id;
-        String blockingActivity = getString(R.string.gesture_blocking_activity);
-        mGestureBlockingActivity = TextUtils.isEmpty(blockingActivity) ? null :
-                ComponentName.unflattenFromString(blockingActivity);
-
-        mExclusionListener = new SystemGestureExclusionListenerCompat(mDefaultDisplayId) {
-            @Override
-            @BinderThread
-            public void onExclusionChanged(Region region) {
-                // Assignments are atomic, it should be safe on binder thread
-                mExclusionRegion = region;
-            }
-        };
-
         onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this));
         sConnected = true;
     }
@@ -359,17 +291,18 @@
         if (TestProtocol.sDebugTracing) {
             Log.d(TestProtocol.NO_BACKGROUND_TO_OVERVIEW_TAG, "initInputMonitor 1");
         }
+        disposeEventHandlers();
         if (!mMode.hasGestures || mISystemUiProxy == null) {
             return;
         }
-        disposeEventHandlers();
         if (TestProtocol.sDebugTracing) {
             Log.d(TestProtocol.NO_BACKGROUND_TO_OVERVIEW_TAG, "initInputMonitor 2");
         }
 
         try {
             mInputMonitorCompat = InputMonitorCompat.fromBundle(mISystemUiProxy
-                    .monitorGestureInput("swipe-up", mDefaultDisplayId), KEY_EXTRA_INPUT_MONITOR);
+                    .monitorGestureInput("swipe-up", mDeviceState.getDisplayId()),
+                    KEY_EXTRA_INPUT_MONITOR);
             mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
                     mMainChoreographer, this::onInputEvent);
             if (TestProtocol.sDebugTracing) {
@@ -378,55 +311,8 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Unable to create input monitor", e);
         }
-        initTouchBounds();
-    }
 
-    private int getNavbarSize(String resName) {
-        return ResourceUtils.getNavbarSize(resName, getResources());
-    }
-
-    private void initTouchBounds() {
-        if (!mMode.hasGestures) {
-            return;
-        }
-
-        DefaultDisplay.Info displayInfo = DefaultDisplay.INSTANCE.get(this).getInfo();
-        Point realSize = new Point(displayInfo.realSize);
-        mSwipeTouchRegion.set(0, 0, realSize.x, realSize.y);
-        if (mMode == Mode.NO_BUTTON) {
-            int touchHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
-            mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - touchHeight;
-
-            final int assistantWidth = getResources()
-                    .getDimensionPixelSize(R.dimen.gestures_assistant_width);
-            final float assistantHeight = Math.max(touchHeight,
-                    QuickStepContract.getWindowCornerRadius(getResources()));
-            mAssistantLeftRegion.bottom = mAssistantRightRegion.bottom = mSwipeTouchRegion.bottom;
-            mAssistantLeftRegion.top = mAssistantRightRegion.top =
-                    mSwipeTouchRegion.bottom - assistantHeight;
-
-            mAssistantLeftRegion.left = 0;
-            mAssistantLeftRegion.right = assistantWidth;
-
-            mAssistantRightRegion.right = mSwipeTouchRegion.right;
-            mAssistantRightRegion.left = mSwipeTouchRegion.right - assistantWidth;
-        } else {
-            mAssistantLeftRegion.setEmpty();
-            mAssistantRightRegion.setEmpty();
-            switch (displayInfo.rotation) {
-                case Surface.ROTATION_90:
-                    mSwipeTouchRegion.left = mSwipeTouchRegion.right
-                            - getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
-                    break;
-                case Surface.ROTATION_270:
-                    mSwipeTouchRegion.right = mSwipeTouchRegion.left
-                            + getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
-                    break;
-                default:
-                    mSwipeTouchRegion.top = mSwipeTouchRegion.bottom
-                            - getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
-            }
-        }
+        mDeviceState.updateGestureTouchRegions();
     }
 
     @Override
@@ -434,43 +320,17 @@
         if (TestProtocol.sDebugTracing) {
             Log.d(TestProtocol.NO_BACKGROUND_TO_OVERVIEW_TAG, "onNavigationModeChanged " + newMode);
         }
-        if (mMode.hasGestures != newMode.hasGestures) {
-            if (newMode.hasGestures) {
-                DefaultDisplay.INSTANCE.get(this).addChangeListener(this);
-            } else {
-                DefaultDisplay.INSTANCE.get(this).removeChangeListener(this);
-            }
-        }
         mMode = newMode;
-
-        disposeEventHandlers();
         initInputMonitor();
-
-        if (mMode == Mode.NO_BUTTON) {
-            mExclusionListener.register();
-        } else {
-            mExclusionListener.unregister();
-        }
     }
 
-    @Override
-    public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) {
-        if (info.id != mDefaultDisplayId) {
-            return;
-        }
-
-        initTouchBounds();
-    }
-
-    private void initWhenUserUnlocked() {
+    public void onUserUnlocked() {
         mRecentsModel = RecentsModel.INSTANCE.get(this);
-        mOverviewComponentObserver = new OverviewComponentObserver(this);
+        mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
 
         mOverviewCommandHelper = new OverviewCommandHelper(this, mOverviewComponentObserver);
         mOverviewInteractionState = OverviewInteractionState.INSTANCE.get(this);
-        mTaskOverlayFactory = TaskOverlayFactory.INSTANCE.get(this);
         mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
-        mIsUserUnlocked = true;
 
         sSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver);
         mInputConsumer.registerInputConsumer();
@@ -482,13 +342,11 @@
         // new ModelPreload().start(this);
         mBackGestureNotificationCounter = Math.max(0, Utilities.getDevicePrefs(this)
                 .getInt(KEY_BACK_NOTIFICATION_COUNT, MAX_BACK_NOTIFICATION_COUNT));
-
-        Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver);
     }
 
     @UiThread
     private void onSystemUiProxySet() {
-        if (mIsUserUnlocked) {
+        if (mDeviceState.isUserUnlocked()) {
             mRecentsModel.setSystemUiProxy(mISystemUiProxy);
             mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy);
         }
@@ -496,37 +354,32 @@
 
     @UiThread
     private void onSystemUiFlagsChanged() {
-        if (mIsUserUnlocked) {
-            mOverviewInteractionState.setSystemUiStateFlags(mSystemUiStateFlags);
-            mOverviewComponentObserver.onSystemUiStateChanged(mSystemUiStateFlags);
+        if (mDeviceState.isUserUnlocked()) {
+            mOverviewInteractionState.setSystemUiStateFlags(mDeviceState.getSystemUiStateFlags());
+            mOverviewComponentObserver.onSystemUiStateChanged();
         }
     }
 
     @UiThread
     private void onAssistantVisibilityChanged() {
-        if (mIsUserUnlocked) {
+        if (mDeviceState.isUserUnlocked()) {
             mOverviewComponentObserver.getActivityControlHelper().onAssistantVisibilityChanged(
-                    mLastAssistantVisibility);
+                    mDeviceState.getAssistantVisibility());
         }
     }
 
     @Override
     public void onDestroy() {
         sIsInitialized = false;
-        if (mIsUserUnlocked) {
+        if (mDeviceState.isUserUnlocked()) {
             mInputConsumer.unregisterInputConsumer();
             mOverviewComponentObserver.onDestroy();
         }
         disposeEventHandlers();
-        if (mMode.hasGestures) {
-            DefaultDisplay.INSTANCE.get(this).removeChangeListener(this);
-        }
+        SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this);
+        mDeviceState.destroy();
 
         sConnected = false;
-        Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver);
-        SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this);
-        mExclusionListener.unregister();
-
         super.onDestroy();
     }
 
@@ -551,14 +404,14 @@
             mLogId = TOUCH_INTERACTION_LOG.generateAndSetLogId();
             sSwipeSharedState.setLogTraceId(mLogId);
 
-            if (mSwipeTouchRegion.contains(event.getX(), event.getY())) {
+            if (mDeviceState.isInSwipeUpTouchRegion(event)) {
                 boolean useSharedState = mConsumer.useSharedSwipeState();
                 mConsumer.onConsumerAboutToBeSwitched();
                 mConsumer = newConsumer(useSharedState, event);
                 TOUCH_INTERACTION_LOG.addLog("setInputConsumer", mConsumer.getType());
                 mUncheckedConsumer = mConsumer;
-            } else if (mIsUserUnlocked && mMode == Mode.NO_BUTTON
-                    && canTriggerAssistantAction(event)) {
+            } else if (mDeviceState.isUserUnlocked() && mMode == Mode.NO_BUTTON
+                    && mDeviceState.canTriggerAssistantAction(event)) {
                 // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we should
                 // not interrupt it. QuickSwitch assumes that interruption can only happen if the
                 // next gesture is also quick switch.
@@ -576,27 +429,11 @@
         DejankBinderTracker.disallowBinderTrackingInTests();
     }
 
-    private boolean validSystemUiFlags() {
-        return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
-                && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0
-                && (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0
-                && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
-                        || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0);
-    }
-
-    private boolean canTriggerAssistantAction(MotionEvent ev) {
-        return mAssistantAvailable
-                && !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
-                && (mAssistantLeftRegion.contains(ev.getX(), ev.getY()) ||
-                    mAssistantRightRegion.contains(ev.getX(), ev.getY()))
-                && !ActivityManagerWrapper.getInstance().isLockToAppActive();
-    }
-
     private InputConsumer newConsumer(boolean useSharedState, MotionEvent event) {
-        boolean isInValidSystemUiState = validSystemUiFlags();
+        boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
 
-        if (!mIsUserUnlocked) {
-            if (isInValidSystemUiState) {
+        if (!mDeviceState.isUserUnlocked()) {
+            if (canStartSystemGesture) {
                 // This handles apps launched in direct boot mode (e.g. dialer) as well as apps
                 // launched while device is locked even after exiting direct boot mode (e.g. camera).
                 return createDeviceLockedInputConsumer(mAM.getRunningTask(ACTIVITY_TYPE_ASSISTANT));
@@ -607,29 +444,28 @@
 
         // When using sharedState, bypass systemState check as this is a followup gesture and the
         // first gesture started in a valid system state.
-        InputConsumer base = isInValidSystemUiState || useSharedState
+        InputConsumer base = canStartSystemGesture || useSharedState
                 ? newBaseConsumer(useSharedState, event) : mResetGestureInputConsumer;
         if (mMode == Mode.NO_BUTTON) {
             final ActivityControlHelper activityControl =
                     mOverviewComponentObserver.getActivityControlHelper();
-            if (canTriggerAssistantAction(event)) {
+            if (mDeviceState.canTriggerAssistantAction(event)) {
                 base = new AssistantInputConsumer(this, mISystemUiProxy, activityControl, base,
                         mInputMonitorCompat);
             }
 
-            if ((mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0) {
+            if (mDeviceState.isScreenPinningActive()) {
                 // Note: we only allow accessibility to wrap this, and it replaces the previous
                 // base input consumer (which should be NO_OP anyway since topTaskLocked == true).
                 base = new ScreenPinnedInputConsumer(this, mISystemUiProxy, activityControl);
             }
 
-            if ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0) {
-                base = new AccessibilityInputConsumer(this, mISystemUiProxy,
-                        (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0, base,
-                        mInputMonitorCompat, mSwipeTouchRegion);
+            if (mDeviceState.isAccessibilityMenuAvailable()) {
+                base = new AccessibilityInputConsumer(this, mDeviceState, mISystemUiProxy, base,
+                        mInputMonitorCompat);
             }
         } else {
-            if ((mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0) {
+            if (mDeviceState.isScreenPinningActive()) {
                 base = mResetGestureInputConsumer;
             }
         }
@@ -642,7 +478,7 @@
         if (!useSharedState) {
             sSwipeSharedState.clearAllState(false /* finishAnimation */);
         }
-        if ((mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0) {
+        if (mDeviceState.isKeyguardShowingOccluded()) {
             // This handles apps showing over the lockscreen (e.g. camera)
             return createDeviceLockedInputConsumer(runningTaskInfo);
         }
@@ -678,8 +514,7 @@
             return createOverviewInputConsumer(event);
         } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityControl.isInLiveTileMode()) {
             return createOverviewInputConsumer(event);
-        } else if (mGestureBlockingActivity != null && runningTaskInfo != null
-                && mGestureBlockingActivity.equals(runningTaskInfo.topActivity)) {
+        } else if (mDeviceState.isGestureBlockedActivity(runningTaskInfo)) {
             return mResetGestureInputConsumer;
         } else {
             return createOtherActivityInputConsumer(event, runningTaskInfo);
@@ -692,13 +527,6 @@
                 && (info.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
     }
 
-    private boolean disableHorizontalSwipe(MotionEvent event) {
-        // mExclusionRegion can change on binder thread, use a local instance here.
-        Region exclusionRegion = mExclusionRegion;
-        return mMode == Mode.NO_BUTTON && exclusionRegion != null
-                && exclusionRegion.contains((int) event.getX(), (int) event.getY());
-    }
-
     private InputConsumer createOtherActivityInputConsumer(MotionEvent event,
             RunningTaskInfo runningTaskInfo) {
 
@@ -711,19 +539,20 @@
             shouldDefer = !sSwipeSharedState.recentsAnimationFinishInterrupted;
             factory = mFallbackNoButtonFactory;
         } else {
-            shouldDefer = activityControlHelper.deferStartingActivity(mActiveNavBarRegion, event);
+            shouldDefer = activityControlHelper.deferStartingActivity(mDeviceState, event);
             factory = mWindowTreansformFactory;
         }
 
-        return new OtherActivityInputConsumer(this, runningTaskInfo, shouldDefer,
-                this::onConsumerInactive, sSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion,
-                disableHorizontalSwipe(event), activityControlHelper, factory, mLogId);
+        final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
+        return new OtherActivityInputConsumer(this, mDeviceState, runningTaskInfo, shouldDefer,
+                this::onConsumerInactive, sSwipeSharedState, mInputMonitorCompat,
+                disableHorizontalSwipe, activityControlHelper, factory, mLogId);
     }
 
     private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) {
         if (mMode == Mode.NO_BUTTON && taskInfo != null) {
-            return new DeviceLockedInputConsumer(this, sSwipeSharedState, mInputMonitorCompat,
-                    mSwipeTouchRegion, taskInfo.taskId, mLogId);
+            return new DeviceLockedInputConsumer(this, mDeviceState, sSwipeSharedState,
+                    mInputMonitorCompat, taskInfo.taskId, mLogId);
         } else {
             return mResetGestureInputConsumer;
         }
@@ -741,8 +570,9 @@
             return new OverviewInputConsumer(activity, mInputMonitorCompat,
                     false /* startingInActivityBounds */, activityControl);
         } else {
+            final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
             return new OverviewWithoutFocusInputConsumer(activity, mInputMonitorCompat,
-                    activityControl, disableHorizontalSwipe(event));
+                    activityControl, disableHorizontalSwipe);
         }
     }
 
@@ -757,7 +587,7 @@
     }
 
     private void preloadOverview(boolean fromInit) {
-        if (!mIsUserUnlocked) {
+        if (!mDeviceState.isUserUnlocked()) {
             return;
         }
         if (!mMode.hasGestures && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
@@ -793,7 +623,7 @@
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
-        if (!mIsUserUnlocked) {
+        if (!mDeviceState.isUserUnlocked()) {
             return;
         }
         final ActivityControlHelper activityControl =
@@ -826,15 +656,9 @@
             }
         } else {
             // Dump everything
+            mDeviceState.dump(pw);
             pw.println("TouchState:");
             pw.println("  navMode=" + mMode);
-            pw.println("  validSystemUiFlags=" + validSystemUiFlags());
-            pw.println("  systemUiFlags=" + mSystemUiStateFlags);
-            pw.println("  systemUiFlagsDesc="
-                    + QuickStepContract.getSystemUiStateString(mSystemUiStateFlags));
-            pw.println("  assistantAvailable=" + mAssistantAvailable);
-            pw.println("  assistantDisabled="
-                    + QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags));
             boolean resumed = mOverviewComponentObserver != null
                     && mOverviewComponentObserver.getActivityControlHelper().isResumed();
             pw.println("  resumed=" + resumed);
@@ -870,7 +694,7 @@
 
     private BaseSwipeUpHandler createWindowTransformSwipeHandler(RunningTaskInfo runningTask,
             long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask) {
-        return  new WindowTransformSwipeHandler(runningTask, this, touchTimeMs,
+        return  new WindowTransformSwipeHandler(mDeviceState, runningTask, this, touchTimeMs,
                 mOverviewComponentObserver, continuingLastGesture, mInputConsumer, mRecentsModel);
     }
 
@@ -882,7 +706,7 @@
 
     protected boolean shouldNotifyBackGesture() {
         return mBackGestureNotificationCounter > 0 &&
-                mGestureBlockingActivity != null;
+                mDeviceState.getGestureBlockedActivityPackage() != null;
     }
 
     @WorkerThread
@@ -892,7 +716,7 @@
             Utilities.getDevicePrefs(this).edit()
                     .putInt(KEY_BACK_NOTIFICATION_COUNT, mBackGestureNotificationCounter).apply();
             sendBroadcast(new Intent(NOTIFY_ACTION_BACK).setPackage(
-                    mGestureBlockingActivity.getPackageName()));
+                    mDeviceState.getGestureBlockedActivityPackage()));
         }
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index fd1ed62..5cf987a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -35,7 +35,6 @@
 import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.NEW_TASK;
 import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.RECENTS;
 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
@@ -198,6 +197,8 @@
      */
     private static final int LOG_NO_OP_PAGE_INDEX = -1;
 
+    private RecentsAnimationDeviceState mDeviceState;
+
     private GestureEndTarget mGestureEndTarget;
     // Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
     private RunningWindowAnim mRunningWindowAnim;
@@ -229,11 +230,12 @@
     private final long mTouchTimeMs;
     private long mLauncherFrameDrawnTime;
 
-    public WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context,
-            long touchTimeMs, OverviewComponentObserver overviewComponentObserver,
-            boolean continuingLastGesture,
+    public WindowTransformSwipeHandler(RecentsAnimationDeviceState deviceState,
+            RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs,
+            OverviewComponentObserver overviewComponentObserver, boolean continuingLastGesture,
             InputConsumerController inputConsumer, RecentsModel recentsModel) {
         super(context, overviewComponentObserver, recentsModel, inputConsumer, runningTaskInfo.id);
+        mDeviceState = deviceState;
         mTouchTimeMs = touchTimeMs;
         mContinuingLastGesture = continuingLastGesture;
         initStateCallbacks();
@@ -755,9 +757,7 @@
             }
         }
 
-        int stateFlags = OverviewInteractionState.INSTANCE.get(mActivity).getSystemUiStateFlags();
-        if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0
-                && (endTarget == RECENTS || endTarget == LAST_TASK)) {
+        if (mDeviceState.isOverviewDisabled() && (endTarget == RECENTS || endTarget == LAST_TASK)) {
             return LAST_TASK;
         }
         return endTarget;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java
index 1f73a28..92bcfb5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java
@@ -23,7 +23,6 @@
 import static android.view.MotionEvent.ACTION_UP;
 
 import android.content.Context;
-import android.graphics.RectF;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.Display;
@@ -32,12 +31,13 @@
 import android.view.ViewConfiguration;
 
 import com.android.launcher3.R;
+import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.util.MotionPauseDetector;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.system.InputMonitorCompat;
 
 /**
- * Touch consumer for two finger swipe actions for accessibility actions
+ * Input consumer for two finger swipe actions for accessibility actions
  */
 public class AccessibilityInputConsumer extends DelegateInputConsumer {
 
@@ -46,8 +46,7 @@
     private final ISystemUiProxy mSystemUiProxy;
     private final VelocityTracker mVelocityTracker;
     private final MotionPauseDetector mMotionPauseDetector;
-    private final boolean mAllowLongClick;
-    private final RectF mSwipeTouchRegion;
+    private final RecentsAnimationDeviceState mDeviceState;
 
     private final float mMinGestureDistance;
     private final float mMinFlingVelocity;
@@ -56,19 +55,17 @@
     private float mDownY;
     private float mTotalY;
 
-    public AccessibilityInputConsumer(Context context, ISystemUiProxy systemUiProxy,
-            boolean allowLongClick, InputConsumer delegate, InputMonitorCompat inputMonitor,
-            RectF swipeTouchRegion) {
+    public AccessibilityInputConsumer(Context context, RecentsAnimationDeviceState deviceState,
+            ISystemUiProxy systemUiProxy, InputConsumer delegate, InputMonitorCompat inputMonitor) {
         super(delegate, inputMonitor);
         mSystemUiProxy = systemUiProxy;
         mVelocityTracker = VelocityTracker.obtain();
         mMinGestureDistance = context.getResources()
                 .getDimension(R.dimen.accessibility_gesture_min_swipe_distance);
         mMinFlingVelocity = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();
-        mSwipeTouchRegion = swipeTouchRegion;
+        mDeviceState = deviceState;
 
         mMotionPauseDetector = new MotionPauseDetector(context);
-        mAllowLongClick = allowLongClick;
     }
 
     @Override
@@ -103,7 +100,7 @@
             case ACTION_POINTER_DOWN: {
                 if (mState == STATE_INACTIVE) {
                     int pointerIndex = ev.getActionIndex();
-                    if (mSwipeTouchRegion.contains(ev.getX(pointerIndex), ev.getY(pointerIndex))
+                    if (mDeviceState.isInSwipeUpTouchRegion(ev, pointerIndex)
                             && mDelegate.allowInterceptByParent()) {
                         setActive(ev);
 
@@ -116,7 +113,7 @@
                 break;
             }
             case ACTION_MOVE: {
-                if (mState == STATE_ACTIVE && mAllowLongClick) {
+                if (mState == STATE_ACTIVE && mDeviceState.isAccessibilityMenuShortcutAvailable()) {
                     int pointerIndex = ev.findPointerIndex(mActivePointerId);
                     if (pointerIndex == -1) {
                         break;
@@ -130,7 +127,8 @@
             case ACTION_UP:
                 if (mState == STATE_ACTIVE) {
                     try {
-                        if (mAllowLongClick && mMotionPauseDetector.isPaused()) {
+                        if (mDeviceState.isAccessibilityMenuShortcutAvailable()
+                                && mMotionPauseDetector.isPaused()) {
                             mSystemUiProxy.notifyAccessibilityButtonLongClicked();
                         } else {
                             mTotalY += (ev.getY() - mDownY);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index 536470b..ba2d6d1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -32,7 +32,6 @@
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
@@ -42,6 +41,7 @@
 import com.android.launcher3.util.DefaultDisplay;
 import com.android.quickstep.LockScreenRecentsActivity;
 import com.android.quickstep.MultiStateCallback;
+import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.SwipeSharedState;
 import com.android.quickstep.util.AppWindowAnimationHelper;
 import com.android.quickstep.util.RecentsAnimationCallbacks;
@@ -73,6 +73,7 @@
             getFlagForIndex(1, "STATE_HANDLER_INVALIDATED");
 
     private final Context mContext;
+    private final RecentsAnimationDeviceState mDeviceState;
     private final float mTouchSlopSquared;
     private final SwipeSharedState mSwipeSharedState;
     private final InputMonitorCompat mInputMonitorCompat;
@@ -83,7 +84,6 @@
     private final AppWindowAnimationHelper.TransformParams mTransformParams;
     private final Point mDisplaySize;
     private final MultiStateCallback mStateCallback;
-    private final RectF mSwipeTouchRegion;
     public final int mRunningTaskId;
 
     private VelocityTracker mVelocityTracker;
@@ -93,17 +93,17 @@
 
     private RecentsAnimationTargets mTargetSet;
 
-    public DeviceLockedInputConsumer(Context context, SwipeSharedState swipeSharedState,
-            InputMonitorCompat inputMonitorCompat, RectF swipeTouchRegion, int runningTaskId,
-            int logId) {
+    public DeviceLockedInputConsumer(Context context, RecentsAnimationDeviceState deviceState,
+            SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat,
+            int runningTaskId, int logId) {
         mContext = context;
+        mDeviceState = deviceState;
         mTouchSlopSquared = squaredTouchSlop(context);
         mSwipeSharedState = swipeSharedState;
         mAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
         mLogId = logId;
         mTransformParams = new AppWindowAnimationHelper.TransformParams();
         mInputMonitorCompat = inputMonitorCompat;
-        mSwipeTouchRegion = swipeTouchRegion;
         mRunningTaskId = runningTaskId;
 
         // Do not use DeviceProfile as the user data might be locked
@@ -139,7 +139,7 @@
                 if (!mThresholdCrossed) {
                     // Cancel interaction in case of multi-touch interaction
                     int ptrIdx = ev.getActionIndex();
-                    if (!mSwipeTouchRegion.contains(ev.getX(ptrIdx), ev.getY(ptrIdx))) {
+                    if (!mDeviceState.isInSwipeUpTouchRegion(ev, ptrIdx)) {
                         int action = ev.getAction();
                         ev.setAction(ACTION_CANCEL);
                         finishTouchTracking(ev);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index e4d898b..6776e84 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -38,7 +38,6 @@
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.graphics.PointF;
-import android.graphics.RectF;
 import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
@@ -55,6 +54,7 @@
 import com.android.quickstep.ActivityControlHelper;
 import com.android.quickstep.BaseSwipeUpHandler;
 import com.android.quickstep.BaseSwipeUpHandler.Factory;
+import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.SwipeSharedState;
 import com.android.quickstep.SysUINavigationMode;
 import com.android.quickstep.SysUINavigationMode.Mode;
@@ -79,12 +79,12 @@
     // TODO: Move to quickstep contract
     public static final float QUICKSTEP_TOUCH_SLOP_RATIO = 3;
 
+    private final RecentsAnimationDeviceState mDeviceState;
     private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher();
     private final RunningTaskInfo mRunningTask;
     private final SwipeSharedState mSwipeSharedState;
     private final InputMonitorCompat mInputMonitorCompat;
     private final SysUINavigationMode.Mode mMode;
-    private final RectF mSwipeTouchRegion;
     private final ActivityControlHelper mActivityControlHelper;
 
     private final BaseSwipeUpHandler.Factory mHandlerFactory;
@@ -124,19 +124,19 @@
     };
     private int mLogId;
 
-    public OtherActivityInputConsumer(Context base, RunningTaskInfo runningTaskInfo,
-            boolean isDeferredDownTarget, Consumer<OtherActivityInputConsumer> onCompleteCallback,
+    public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState,
+            RunningTaskInfo runningTaskInfo, boolean isDeferredDownTarget,
+            Consumer<OtherActivityInputConsumer> onCompleteCallback,
             SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat,
-            RectF swipeTouchRegion, boolean disableHorizontalSwipe,
-            ActivityControlHelper activityControlHelper,
+            boolean disableHorizontalSwipe, ActivityControlHelper activityControlHelper,
             Factory handlerFactory, int logId) {
         super(base);
         mLogId = logId;
 
+        mDeviceState = deviceState;
         mMainThreadHandler = new Handler(Looper.getMainLooper());
         mRunningTask = runningTaskInfo;
         mMode = SysUINavigationMode.getMode(base);
-        mSwipeTouchRegion = swipeTouchRegion;
         mHandlerFactory = handlerFactory;
         mActivityControlHelper = activityControlHelper;
 
@@ -217,7 +217,7 @@
                 if (!mPassedPilferInputSlop) {
                     // Cancel interaction in case of multi-touch interaction
                     int ptrIdx = ev.getActionIndex();
-                    if (!mSwipeTouchRegion.contains(ev.getX(ptrIdx), ev.getY(ptrIdx))) {
+                    if (!mDeviceState.isInSwipeUpTouchRegion(ev, ptrIdx)) {
                         forceCancelGesture(ev);
                     }
                 }
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index 5fb5fd7..132d6ab 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.graphics.Region;
 import android.os.Build;
 import android.view.MotionEvent;
 import android.view.View;
@@ -81,7 +80,7 @@
 
     boolean shouldMinimizeSplitScreen();
 
-    default boolean deferStartingActivity(Region activeNavBarRegion, MotionEvent ev) {
+    default boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
         return true;
     }
 
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 88a4eb6..331183a 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -22,7 +22,6 @@
 
 import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter;
 import static com.android.systemui.shared.system.PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
 
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -57,6 +56,7 @@
         }
     };
     private final Context mContext;
+    private final RecentsAnimationDeviceState mDeviceState;
     private final Intent mCurrentHomeIntent;
     private final Intent mMyHomeIntent;
     private final Intent mFallbackIntent;
@@ -64,12 +64,13 @@
     private String mUpdateRegisteredPackage;
     private ActivityControlHelper mActivityControlHelper;
     private Intent mOverviewIntent;
-    private int mSystemUiStateFlags;
     private boolean mIsHomeAndOverviewSame;
     private boolean mIsDefaultHome;
+    private boolean mIsHomeDisabled;
 
-    public OverviewComponentObserver(Context context) {
+    public OverviewComponentObserver(Context context, RecentsAnimationDeviceState deviceState) {
         mContext = context;
+        mDeviceState = deviceState;
 
         mCurrentHomeIntent = new Intent(Intent.ACTION_MAIN)
                 .addCategory(Intent.CATEGORY_HOME)
@@ -98,11 +99,8 @@
         updateOverviewTargets();
     }
 
-    public void onSystemUiStateChanged(int stateFlags) {
-        boolean homeDisabledChanged = (mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED)
-                != (stateFlags & SYSUI_STATE_HOME_DISABLED);
-        mSystemUiStateFlags = stateFlags;
-        if (homeDisabledChanged) {
+    public void onSystemUiStateChanged() {
+        if (mDeviceState.isHomeDisabled() != mIsHomeDisabled) {
             updateOverviewTargets();
         }
     }
@@ -115,6 +113,7 @@
         ComponentName defaultHome = PackageManagerWrapper.getInstance()
                 .getHomeActivities(new ArrayList<>());
 
+        mIsHomeDisabled = mDeviceState.isHomeDisabled();
         mIsDefaultHome = Objects.equals(mMyHomeIntent.getComponent(), defaultHome);
 
         // Set assistant visibility to 0 from launcher's perspective, ensures any elements that
@@ -124,8 +123,7 @@
             mActivityControlHelper.onAssistantVisibilityChanged(0.f);
         }
 
-        if ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
-                && (defaultHome == null || mIsDefaultHome)) {
+        if (!mDeviceState.isHomeDisabled() && (defaultHome == null || mIsDefaultHome)) {
             // User default home is same as out home app. Use Overview integrated in Launcher.
             mActivityControlHelper = new LauncherActivityControllerHelper();
             mIsHomeAndOverviewSame = true;
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index 858c3b6..17462ab 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -86,6 +86,7 @@
         mBgHandler.obtainMessage(MSG_SET_PROXY, proxy).sendToTarget();
     }
 
+    // TODO(141886704): See if we can remove this
     public void setSystemUiStateFlags(int stateFlags) {
         mSystemUiStateFlags = stateFlags;
     }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
new file mode 100644
index 0000000..9b094f6
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 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.
+ */
+package com.android.quickstep;
+
+import static android.content.Intent.ACTION_USER_UNLOCKED;
+import static com.android.launcher3.ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE;
+import static com.android.launcher3.ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE;
+import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
+import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
+
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.os.Process;
+import android.text.TextUtils;
+import android.view.MotionEvent;
+import android.view.Surface;
+import androidx.annotation.BinderThread;
+import com.android.launcher3.R;
+import com.android.launcher3.ResourceUtils;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.DefaultDisplay;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
+import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Manages the state of the system during a swipe up gesture.
+ */
+public class RecentsAnimationDeviceState implements
+        SysUINavigationMode.NavigationModeChangeListener,
+        DefaultDisplay.DisplayInfoChangeListener {
+
+    private Context mContext;
+    private UserManagerCompat mUserManager;
+    private SysUINavigationMode mSysUiNavMode;
+    private DefaultDisplay mDefaultDisplay;
+    private int mDisplayId;
+
+    private @SystemUiStateFlags int mSystemUiStateFlags;
+    private SysUINavigationMode.Mode mMode = THREE_BUTTONS;
+
+    private final RectF mSwipeUpTouchRegion = new RectF();
+    private final Region mDeferredGestureRegion = new Region();
+    private final RectF mAssistantLeftRegion = new RectF();
+    private final RectF mAssistantRightRegion = new RectF();
+    private boolean mAssistantAvailable;
+    private float mAssistantVisibility;
+
+    private boolean mIsUserUnlocked;
+    private final ArrayList<Runnable> mUserUnlockedActions = new ArrayList<>();
+    private final BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+                mIsUserUnlocked = true;
+                notifyUserUnlocked();
+            }
+        }
+    };
+
+    private Region mExclusionRegion;
+    private SystemGestureExclusionListenerCompat mExclusionListener;
+
+    private ComponentName mGestureBlockedActivity;
+
+    public RecentsAnimationDeviceState(Context context) {
+        mContext = context;
+        mUserManager = UserManagerCompat.getInstance(context);
+        mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context);
+        mDefaultDisplay = DefaultDisplay.INSTANCE.get(context);
+        mDisplayId = mDefaultDisplay.getInfo().id;
+
+        // Register for user unlocked if necessary
+        mIsUserUnlocked = mUserManager.isUserUnlocked(Process.myUserHandle());
+        if (!mIsUserUnlocked) {
+            mContext.registerReceiver(mUserUnlockedReceiver,
+                    new IntentFilter(ACTION_USER_UNLOCKED));
+        }
+
+        // Register for exclusion updates
+        mExclusionListener = new SystemGestureExclusionListenerCompat(mDisplayId) {
+            @Override
+            @BinderThread
+            public void onExclusionChanged(Region region) {
+                // Assignments are atomic, it should be safe on binder thread
+                mExclusionRegion = region;
+            }
+        };
+        onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(this));
+
+        // Add any blocked activities
+        String blockingActivity = context.getString(R.string.gesture_blocking_activity);
+        if (!TextUtils.isEmpty(blockingActivity)) {
+            mGestureBlockedActivity = ComponentName.unflattenFromString(blockingActivity);
+        }
+    }
+
+    /**
+     * Cleans up all the registered listeners and receivers.
+     */
+    public void destroy() {
+        Utilities.unregisterReceiverSafely(mContext, mUserUnlockedReceiver);
+        mSysUiNavMode.removeModeChangeListener(this);
+        mDefaultDisplay.removeChangeListener(this);
+        mExclusionListener.unregister();
+    }
+
+    @Override
+    public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) {
+        mDefaultDisplay.removeChangeListener(this);
+        if (newMode.hasGestures) {
+            mDefaultDisplay.addChangeListener(this);
+        }
+
+        if (mMode == NO_BUTTON) {
+            mExclusionListener.register();
+        } else {
+            mExclusionListener.unregister();
+        }
+        mMode = newMode;
+    }
+
+    @Override
+    public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) {
+        if (info.id != getDisplayId()) {
+            return;
+        }
+
+        updateGestureTouchRegions();
+    }
+
+    /**
+     * @return the display id for the display that Launcher is running on.
+     */
+    public int getDisplayId() {
+        return mDisplayId;
+    }
+
+    /**
+     * Adds a callback for when a user is unlocked. If the user is already unlocked, this listener
+     * will be called back immediately.
+     */
+    public void runOnUserUnlocked(Runnable action) {
+        if (mIsUserUnlocked) {
+            action.run();
+        } else {
+            mUserUnlockedActions.add(action);
+        }
+    }
+
+    /**
+     * @return whether the user is unlocked.
+     */
+    public boolean isUserUnlocked() {
+        return mIsUserUnlocked;
+    }
+
+    private void notifyUserUnlocked() {
+        for (Runnable action : mUserUnlockedActions) {
+            action.run();
+        }
+        mUserUnlockedActions.clear();
+        Utilities.unregisterReceiverSafely(mContext, mUserUnlockedReceiver);
+    }
+
+    /**
+     * @return whether the given running task info matches the gesture-blocked activity.
+     */
+    public boolean isGestureBlockedActivity(ActivityManager.RunningTaskInfo runningTaskInfo) {
+        return runningTaskInfo != null
+                && mGestureBlockedActivity.equals(runningTaskInfo.topActivity);
+    }
+
+    /**
+     * @return the package of the gesture-blocked activity or {@code null} if there is none.
+     */
+    public String getGestureBlockedActivityPackage() {
+        return (mGestureBlockedActivity != null)
+                ? mGestureBlockedActivity.getPackageName()
+                : null;
+    }
+
+    /**
+     * Updates the system ui state flags from SystemUI.
+     */
+    public void setSystemUiFlags(int stateFlags) {
+        mSystemUiStateFlags = stateFlags;
+    }
+
+    /**
+     * @return the system ui state flags.
+     */
+    // TODO(141886704): See if we can remove this
+    public @SystemUiStateFlags int getSystemUiStateFlags() {
+        return mSystemUiStateFlags;
+    }
+
+    /**
+     * @return whether SystemUI is in a state where we can start a system gesture.
+     */
+    public boolean canStartSystemGesture() {
+        return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
+                && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0
+                && (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0
+                && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
+                        || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0);
+    }
+
+    /**
+     * @return whether the keyguard is showing and is occluded by an app showing above the keyguard
+     *         (like camera or maps)
+     */
+    public boolean isKeyguardShowingOccluded() {
+        return (mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0;
+    }
+
+    /**
+     * @return whether screen pinning is enabled and active
+     */
+    public boolean isScreenPinningActive() {
+        return (mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0;
+    }
+
+    /**
+     * @return whether lock-task mode is active
+     */
+    public boolean isLockToAppActive() {
+        return ActivityManagerWrapper.getInstance().isLockToAppActive();
+    }
+
+    /**
+     * @return whether the accessibility menu is available.
+     */
+    public boolean isAccessibilityMenuAvailable() {
+        return (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
+    }
+
+    /**
+     * @return whether the accessibility menu shortcut is available.
+     */
+    public boolean isAccessibilityMenuShortcutAvailable() {
+        return (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
+    }
+
+    /**
+     * @return whether home is disabled (either by SUW/SysUI/device policy)
+     */
+    public boolean isHomeDisabled() {
+        return (mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) != 0;
+    }
+
+    /**
+     * @return whether overview is disabled (either by SUW/SysUI/device policy)
+     */
+    public boolean isOverviewDisabled() {
+        return (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0;
+    }
+
+    /**
+     * Updates the regions for detecting the swipe up/quickswitch and assistant gestures.
+     */
+    public void updateGestureTouchRegions() {
+        if (!mMode.hasGestures) {
+            return;
+        }
+
+        Resources res = mContext.getResources();
+        DefaultDisplay.Info displayInfo = mDefaultDisplay.getInfo();
+        Point realSize = new Point(displayInfo.realSize);
+        mSwipeUpTouchRegion.set(0, 0, realSize.x, realSize.y);
+        if (mMode == NO_BUTTON) {
+            int touchHeight = ResourceUtils.getNavbarSize(NAVBAR_BOTTOM_GESTURE_SIZE, res);
+            mSwipeUpTouchRegion.top = mSwipeUpTouchRegion.bottom - touchHeight;
+
+            final int assistantWidth = res.getDimensionPixelSize(R.dimen.gestures_assistant_width);
+            final float assistantHeight = Math.max(touchHeight,
+                    QuickStepContract.getWindowCornerRadius(res));
+            mAssistantLeftRegion.bottom = mAssistantRightRegion.bottom = mSwipeUpTouchRegion.bottom;
+            mAssistantLeftRegion.top = mAssistantRightRegion.top =
+                    mSwipeUpTouchRegion.bottom - assistantHeight;
+
+            mAssistantLeftRegion.left = 0;
+            mAssistantLeftRegion.right = assistantWidth;
+
+            mAssistantRightRegion.right = mSwipeUpTouchRegion.right;
+            mAssistantRightRegion.left = mSwipeUpTouchRegion.right - assistantWidth;
+        } else {
+            mAssistantLeftRegion.setEmpty();
+            mAssistantRightRegion.setEmpty();
+            switch (displayInfo.rotation) {
+                case Surface.ROTATION_90:
+                    mSwipeUpTouchRegion.left = mSwipeUpTouchRegion.right
+                            - ResourceUtils.getNavbarSize(NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE, res);
+                    break;
+                case Surface.ROTATION_270:
+                    mSwipeUpTouchRegion.right = mSwipeUpTouchRegion.left
+                            + ResourceUtils.getNavbarSize(NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE, res);
+                    break;
+                default:
+                    mSwipeUpTouchRegion.top = mSwipeUpTouchRegion.bottom
+                            - ResourceUtils.getNavbarSize(NAVBAR_BOTTOM_GESTURE_SIZE, res);
+            }
+        }
+    }
+
+    /**
+     * @return whether the coordinates of the {@param event} is in the swipe up gesture region.
+     */
+    public boolean isInSwipeUpTouchRegion(MotionEvent event) {
+        return mSwipeUpTouchRegion.contains(event.getX(), event.getY());
+    }
+
+    /**
+     * @return whether the coordinates of the {@param event} with the given {@param pointerIndex}
+     *         is in the swipe up gesture region.
+     */
+    public boolean isInSwipeUpTouchRegion(MotionEvent event, int pointerIndex) {
+        return mSwipeUpTouchRegion.contains(event.getX(pointerIndex), event.getY(pointerIndex));
+    }
+
+    /**
+     * Sets the region in screen space where the gestures should be deferred (ie. due to specific
+     * nav bar ui).
+     */
+    public void setDeferredGestureRegion(Region deferredGestureRegion) {
+        mDeferredGestureRegion.set(deferredGestureRegion);
+    }
+
+    /**
+     * @return whether the given {@param event} is in the deferred gesture region indicating that
+     *         the Launcher should not immediately start the recents animation until the gesture
+     *         passes a certain threshold.
+     */
+    public boolean isInDeferredGestureRegion(MotionEvent event) {
+        return mDeferredGestureRegion.contains((int) event.getX(), (int) event.getY());
+    }
+
+    /**
+     * @return whether the given {@param event} is in the app-requested gesture-exclusion region.
+     *         This is only used for quickswitch, and not swipe up.
+     */
+    public boolean isInExclusionRegion(MotionEvent event) {
+        // mExclusionRegion can change on binder thread, use a local instance here.
+        Region exclusionRegion = mExclusionRegion;
+        return mMode == NO_BUTTON && exclusionRegion != null
+                && exclusionRegion.contains((int) event.getX(), (int) event.getY());
+    }
+
+    /**
+     * Sets whether the assistant is available.
+     */
+    public void setAssistantAvailable(boolean assistantAvailable) {
+        mAssistantAvailable = assistantAvailable;
+    }
+
+    /**
+     * Sets the visibility fraction of the assistant.
+     */
+    public void setAssistantVisibility(float visibility) {
+        mAssistantVisibility = visibility;
+    }
+
+    /**
+     * @return the visibility fraction of the assistant.
+     */
+    public float getAssistantVisibility() {
+        return mAssistantVisibility;
+    }
+
+    /**
+     * @param ev An ACTION_DOWN motion event
+     * @return whether the given motion event can trigger the assistant.
+     */
+    public boolean canTriggerAssistantAction(MotionEvent ev) {
+        return mAssistantAvailable
+                && !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
+                && (mAssistantLeftRegion.contains(ev.getX(), ev.getY())
+                        || mAssistantRightRegion.contains(ev.getX(), ev.getY()))
+                && !isLockToAppActive();
+    }
+
+    public void dump(PrintWriter pw) {
+        pw.println("DeviceState:");
+        pw.println("  canStartSystemGesture=" + canStartSystemGesture());
+        pw.println("  systemUiFlags=" + mSystemUiStateFlags);
+        pw.println("  systemUiFlagsDesc="
+                + QuickStepContract.getSystemUiStateString(mSystemUiStateFlags));
+        pw.println("  assistantAvailable=" + mAssistantAvailable);
+        pw.println("  assistantDisabled="
+                + QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags));
+    }
+}