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

Commit 727a2180 authored by Jeremy Sim's avatar Jeremy Sim
Browse files

Fix various issues with offscreen touch zones

1) When touch zones were released, the ViewHost was being released, but not the root leash. Now the root leash is removed as well.
2) The swap animation was calculating the wrong end position for the divider, because it measured from the screen edge instead of accounting for the offscreen app's offset.
3) The touch layer was being animated while still active, meaning that if the surface passed under the user's finger, it would register a touch. Now the touch layer is deactivated and removed prior to animation.

Fixes: 391868062
Fixes: 391866253
Flag: com.android.wm.shell.enable_flexible_two_app_split
Test: App surfaces no longer jump cut when swapping on the right side, and winscope is clear of any extra leashes.
Change-Id: I37103658c9082cfa02a870cb8ab30d0baae7c04a
parent 9cf8d0f7
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ public class OffscreenTouchZone {
    /** The function that will be run when this zone is tapped. */
    private final Runnable mOnClickRunnable;
    private SurfaceControlViewHost mViewHost;
    private SurfaceControl mLeash;

    /**
     * @param isTopLeft Whether the desired touch zone will be on the top/left or the bottom/right
@@ -96,6 +97,7 @@ public class OffscreenTouchZone {
                .setCallsite("OffscreenTouchZone::init");
        builder.setParent(stageRoot);
        SurfaceControl leash = builder.build();
        mLeash = leash;

        // Create a ViewHost that will hold our view.
        WindowlessWindowManager wwm = new WindowlessWindowManager(config, leash, null);
@@ -117,10 +119,14 @@ public class OffscreenTouchZone {
    }

    /** Releases the touch zone when it's no longer needed. */
    void release() {
    void release(SurfaceControl.Transaction t) {
        if (mViewHost != null) {
            mViewHost.release();
        }
        if (mLeash != null) {
            t.remove(mLeash);
            mLeash = null;
        }
    }

    /**
+17 −2
Original line number Diff line number Diff line
@@ -451,7 +451,14 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
            return;
        }

        mOffscreenTouchZones.forEach(OffscreenTouchZone::release);
        // TODO (b/349828130): It would be good to reuse a Transaction from StageCoordinator's
        //  mTransactionPool here, but passing it through SplitLayout and specifically
        //  SplitLayout.release() is complicated because that function is purposely called with a
        //  null value sometimes. When that function is refactored, we should also pass the
        //  Transaction in here.
        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
        mOffscreenTouchZones.forEach(touchZone -> touchZone.release(t));
        t.apply();
        mOffscreenTouchZones.clear();
    }

@@ -965,8 +972,16 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
        final boolean shouldVeil =
                insets.left != 0 || insets.top != 0 || insets.right != 0 || insets.bottom != 0;

        // Find the "left/top"-most position of the app surface -- usually 0, but sometimes negative
        // if the left/top app is offscreen.
        int leftTop = 0;
        if (Flags.enableFlexibleTwoAppSplit()) {
            leftTop = mIsLeftRightSplit ? getTopLeftBounds().left : getTopLeftBounds().top;
        }

        final int dividerPos = mDividerSnapAlgorithm.calculateNonDismissingSnapTarget(
                mIsLeftRightSplit ? getBottomRightBounds().width() : getBottomRightBounds().height()
                leftTop + (mIsLeftRightSplit
                        ? getBottomRightBounds().width() : getBottomRightBounds().height())
        ).position;
        final Rect endBounds1 = new Rect();
        final Rect endBounds2 = new Rect();
+5 −0
Original line number Diff line number Diff line
@@ -1295,6 +1295,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        WindowContainerTransaction noFocus = new WindowContainerTransaction();
        noFocus.setFocusable(mRootTaskInfo.token, false);
        mSyncQueue.queue(noFocus);
        // Remove touch layers, since offscreen apps coming onscreen will not need their touch
        // layers anymore. populateTouchZones() is called in the end callback to inflate new touch
        // layers in the appropriate places.
        mSplitLayout.removeTouchZones();

        mSplitLayout.playSwapAnimation(t, topLeftStage, bottomRightStage,
                insets -> {
@@ -1315,6 +1319,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                    mSyncQueue.runInSync(st -> {
                        mSplitLayout.updateStateWithCurrentPosition();
                        updateSurfaceBounds(mSplitLayout, st, false /* applyResizingOffset */);
                        mSplitLayout.populateTouchZones();

                        // updateSurfaceBounds(), above, officially puts the two apps in their new
                        // stages. Starting on the next frame, all calculations are made using the