Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7623531a authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Avoid NPE when removing fixed rotation transform

The legacy code "checks c.getParent() != null" in resetTransform
to avoid the case such as transition finished after the token is
detached.

While with shell transition, the rotation leash still needs to
be removed but ignore reparent in case the token is detached.

Also extract FixedRotationTransformStateLegacy for legacy
transition. So by default the shell transition can skip the
unnecessary creation of SeamlessRotator.

Bug: 277697318
Test: IncompleteMotionTest
Change-Id: I6e5ebd15a972d88232e7a9a46ff1ab4f557c58d7
parent 7dd18dd3
Loading
Loading
Loading
Loading
+50 −24
Original line number Diff line number Diff line
@@ -119,24 +119,20 @@ class WindowToken extends WindowContainer<WindowState> {
        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,16 +140,48 @@ class WindowToken extends WindowContainer<WindowState> {
         * 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().
        }

        /**
         * Resets the transformation of the window containers which have been rotated. This should
         * 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);
@@ -164,9 +192,9 @@ class WindowToken extends WindowContainer<WindowState> {
            }
        }

        /** 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 @@ class WindowToken extends WindowContainer<WindowState> {
        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 @@ class WindowToken extends WindowContainer<WindowState> {
        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();
            }
        }
        // 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 @@ class WindowToken extends WindowContainer<WindowState> {
    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;
    }