Merge changes I37c8daa6,I5a05b65d,If56347fd

* changes:
  Preload2: Add isSingleThreaded
  Preload2: Fix action inheritance
  Preload2: Abstract out UI
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index b0d45e1d1..be10608df 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -1190,6 +1190,26 @@
         }
 
         /**
+         * Remove a state from the state machine. Will not remove the state if it is currently
+         * active or if it has any children in the hierarchy.
+         * @param state the state to remove
+         */
+        private void removeState(State state) {
+            StateInfo stateInfo = mStateInfo.get(state);
+            if (stateInfo == null || stateInfo.active) {
+                return;
+            }
+            boolean isParent = mStateInfo.values().stream()
+                    .filter(si -> si.parentStateInfo == stateInfo)
+                    .findAny()
+                    .isPresent();
+            if (isParent) {
+                return;
+            }
+            mStateInfo.remove(state);
+        }
+
+        /**
          * Constructor
          *
          * @param looper for dispatching messages
@@ -1337,6 +1357,14 @@
     }
 
     /**
+     * Removes a state from the state machine, unless it is currently active or if it has children.
+     * @param state state to remove
+     */
+    public final void removeState(State state) {
+        mSmHandler.removeState(state);
+    }
+
+    /**
      * Set the initial state. This must be invoked before
      * and messages are sent to the state machine.
      *