Merge "Avoid NPE when removing fixed rotation transform" into udc-dev
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 327483e..da54b15 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -119,24 +119,20 @@
         final DisplayInfo mDisplayInfo;
         final DisplayFrames mDisplayFrames;
         final Configuration mRotatedOverrideConfiguration;
-        final SeamlessRotator mRotator;
+
         /**
          * The tokens that share the same transform. Their end time of transform are the same. The
          * list should at least contain the token who creates this state.
          */
         final ArrayList<WindowToken> mAssociatedTokens = new ArrayList<>(3);
-        final ArrayList<WindowContainer<?>> mRotatedContainers = new ArrayList<>(3);
+
         boolean mIsTransforming = true;
 
         FixedRotationTransformState(DisplayInfo rotatedDisplayInfo,
-                DisplayFrames rotatedDisplayFrames, Configuration rotatedConfig,
-                int currentRotation) {
+                DisplayFrames rotatedDisplayFrames, Configuration rotatedConfig) {
             mDisplayInfo = rotatedDisplayInfo;
             mDisplayFrames = rotatedDisplayFrames;
             mRotatedOverrideConfiguration = rotatedConfig;
-            // This will use unrotate as rotate, so the new and old rotation are inverted.
-            mRotator = new SeamlessRotator(rotatedDisplayInfo.rotation, currentRotation,
-                    rotatedDisplayInfo, true /* applyFixedTransformationHint */);
         }
 
         /**
@@ -144,10 +140,8 @@
          * showing the window in a display with different rotation.
          */
         void transform(WindowContainer<?> container) {
-            mRotator.unrotate(container.getPendingTransaction(), container);
-            if (!mRotatedContainers.contains(container)) {
-                mRotatedContainers.add(container);
-            }
+            // The default implementation assumes shell transition is enabled, so the transform
+            // is done by getOrCreateFixedRotationLeash().
         }
 
         /**
@@ -155,6 +149,40 @@
          * be called when the window has the same rotation as display.
          */
         void resetTransform() {
+            for (int i = mAssociatedTokens.size() - 1; i >= 0; --i) {
+                mAssociatedTokens.get(i).removeFixedRotationLeash();
+            }
+        }
+
+        /** The state may not only be used by self. Make sure to leave the influence by others. */
+        void disassociate(WindowToken token) {
+            mAssociatedTokens.remove(token);
+        }
+    }
+
+    private static class FixedRotationTransformStateLegacy extends FixedRotationTransformState {
+        final SeamlessRotator mRotator;
+        final ArrayList<WindowContainer<?>> mRotatedContainers = new ArrayList<>(3);
+
+        FixedRotationTransformStateLegacy(DisplayInfo rotatedDisplayInfo,
+                DisplayFrames rotatedDisplayFrames, Configuration rotatedConfig,
+                int currentRotation) {
+            super(rotatedDisplayInfo, rotatedDisplayFrames, rotatedConfig);
+            // This will use unrotate as rotate, so the new and old rotation are inverted.
+            mRotator = new SeamlessRotator(rotatedDisplayInfo.rotation, currentRotation,
+                    rotatedDisplayInfo, true /* applyFixedTransformationHint */);
+        }
+
+        @Override
+        void transform(WindowContainer<?> container) {
+            mRotator.unrotate(container.getPendingTransaction(), container);
+            if (!mRotatedContainers.contains(container)) {
+                mRotatedContainers.add(container);
+            }
+        }
+
+        @Override
+        void resetTransform() {
             for (int i = mRotatedContainers.size() - 1; i >= 0; i--) {
                 final WindowContainer<?> c = mRotatedContainers.get(i);
                 // If the window is detached (no parent), its surface may have been released.
@@ -164,9 +192,9 @@
             }
         }
 
-        /** The state may not only be used by self. Make sure to leave the influence by others. */
+        @Override
         void disassociate(WindowToken token) {
-            mAssociatedTokens.remove(token);
+            super.disassociate(token);
             mRotatedContainers.remove(token);
         }
     }
@@ -437,8 +465,11 @@
         if (mFixedRotationTransformState != null) {
             mFixedRotationTransformState.disassociate(this);
         }
-        mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames,
-                new Configuration(config), mDisplayContent.getRotation());
+        config = new Configuration(config);
+        mFixedRotationTransformState = mTransitionController.isShellTransitionsEnabled()
+                ? new FixedRotationTransformState(info, displayFrames, config)
+                : new FixedRotationTransformStateLegacy(info, displayFrames, config,
+                        mDisplayContent.getRotation());
         mFixedRotationTransformState.mAssociatedTokens.add(this);
         mDisplayContent.getDisplayPolicy().simulateLayoutDisplay(displayFrames);
         onFixedRotationStatePrepared();
@@ -508,14 +539,7 @@
         if (state == null) {
             return;
         }
-        if (!mTransitionController.isShellTransitionsEnabled()) {
-            state.resetTransform();
-        } else {
-            // Remove all the leashes
-            for (int i = state.mAssociatedTokens.size() - 1; i >= 0; --i) {
-                state.mAssociatedTokens.get(i).removeFixedRotationLeash();
-            }
-        }
+        state.resetTransform();
         // Clear the flag so if the display will be updated to the same orientation, the transform
         // won't take effect.
         state.mIsTransforming = false;
@@ -589,7 +613,9 @@
     void removeFixedRotationLeash() {
         if (mFixedRotationTransformLeash == null) return;
         final SurfaceControl.Transaction t = getSyncTransaction();
-        t.reparent(getSurfaceControl(), getParentSurfaceControl());
+        if (mSurfaceControl != null) {
+            t.reparent(mSurfaceControl, getParentSurfaceControl());
+        }
         t.remove(mFixedRotationTransformLeash);
         mFixedRotationTransformLeash = null;
     }