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

Commit 62c7846b authored by Matthew Ng's avatar Matthew Ng
Browse files

Secondary split screen app will be next to the navigation bar (1/2)

Refactored docked position code into PhoneWindowManager to determine
which side the docked app should go based on the position of the nav bar
in landscape (as portrait will only have top). Fixed the split screen
entrance animation for quick step's overview.

Change-Id: I30f1be9d791c23f4cd197f17487609964f78fac0
Fixes: 73250406
Test: play around with splitscreen and minimized mode
Test: atest com.android.server.policy.PhoneWindowManagerTest
parent 331a22e3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -344,7 +344,7 @@ public class DividerSnapAlgorithm {
            if (dockedSide == DOCKED_LEFT) {
                position += mInsets.left;
            } else if (dockedSide == DOCKED_RIGHT) {
                position = mDisplayWidth - position - mInsets.right;
                position = mDisplayWidth - position - mInsets.right - mDividerSize;
            }
        }
        mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
+25 −0
Original line number Diff line number Diff line
@@ -26,6 +26,10 @@ import android.util.Log;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;

import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;

import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;

@@ -58,6 +62,11 @@ public class WindowManagerWrapper {
    public static final int TRANSIT_KEYGUARD_OCCLUDE = WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
    public static final int TRANSIT_KEYGUARD_UNOCCLUDE = WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;

    public static final int NAV_BAR_POS_INVALID = -1;
    public static final int NAV_BAR_POS_LEFT = NAV_BAR_LEFT;
    public static final int NAV_BAR_POS_RIGHT = NAV_BAR_RIGHT;
    public static final int NAV_BAR_POS_BOTTOM = NAV_BAR_BOTTOM;

    public static final int ACTIVITY_TYPE_STANDARD = WindowConfiguration.ACTIVITY_TYPE_STANDARD;

    public static final int WINDOWING_MODE_UNDEFINED = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -141,4 +150,20 @@ public class WindowManagerWrapper {
            Log.w(TAG, "Failed to set recents visibility");
        }
    }

    /**
     * @return The side of the screen where navigation bar is positioned.
     * @see #NAV_BAR_POS_RIGHT
     * @see #NAV_BAR_POS_LEFT
     * @see #NAV_BAR_POS_BOTTOM
     * @see #NAV_BAR_POS_INVALID
     */
    public int getNavBarPosition() {
        try {
            return WindowManagerGlobal.getWindowManagerService().getNavBarPosition();
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to get nav bar position");
        }
        return NAV_BAR_POS_INVALID;
    }
}
+42 −8
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -364,14 +366,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
        if (mStableInsets.isEmpty()) {
            SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
        }
        int position = (int) (mState.mRatioPositionBeforeMinimized *
                (isHorizontalDivision() ? mDisplayHeight : mDisplayWidth));
        mSnapAlgorithm = null;
        initializeSnapAlgorithm();

        // Set the snap target before minimized but do not save until divider is attached and not
        // minimized because it does not know its minimized state yet.
        mSnapTargetBeforeMinimized = mSnapAlgorithm.calculateNonDismissingSnapTarget(position);
        repositionSnapTargetBeforeMinimized();
    }

    public WindowManagerProxy getWindowManagerProxy() {
@@ -878,9 +873,36 @@ public class DividerView extends FrameLayout implements OnTouchListener,
    }

    public void notifyDockSideChanged(int newDockSide) {
        int oldDockSide = mDockSide;
        mDockSide = newDockSide;
        mMinimizedShadow.setDockSide(mDockSide);
        requestLayout();

        // Update the snap position to the new docked side with correct insets
        SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
        mMinimizedSnapAlgorithm = null;
        initializeSnapAlgorithm();

        if (oldDockSide == DOCKED_LEFT && mDockSide == DOCKED_RIGHT
                || oldDockSide == DOCKED_RIGHT && mDockSide == DOCKED_LEFT) {
            repositionSnapTargetBeforeMinimized();
        }

        // Landscape to seascape rotation requires minimized to resize docked app correctly
        if (mHomeStackResizable && mDockedStackMinimized) {
            resizeStack(mMinimizedSnapAlgorithm.getMiddleTarget());
        }
    }

    private void repositionSnapTargetBeforeMinimized() {
        int position = (int) (mState.mRatioPositionBeforeMinimized *
                (isHorizontalDivision() ? mDisplayHeight : mDisplayWidth));
        mSnapAlgorithm = null;
        initializeSnapAlgorithm();

        // Set the snap target before minimized but do not save until divider is attached and not
        // minimized because it does not know its minimized state yet.
        mSnapTargetBeforeMinimized = mSnapAlgorithm.calculateNonDismissingSnapTarget(position);
    }

    private void updateDisplayInfo() {
@@ -962,6 +984,12 @@ public class DividerView extends FrameLayout implements OnTouchListener,
        if (mHomeStackResizable && mIsInMinimizeInteraction) {
            calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, mDockSide,
                    mDockedTaskRect);

            // Move a right-docked-app to line up with the divider while dragging it
            if (mDockSide == DOCKED_RIGHT) {
                mDockedTaskRect.offset(Math.max(position, mStableInsets.left - mDividerSize)
                        - mDockedTaskRect.left + mDividerSize, 0);
            }
            calculateBoundsForPosition(mSnapTargetBeforeMinimized.position,
                    DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
            mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedTaskRect,
@@ -976,6 +1004,12 @@ public class DividerView extends FrameLayout implements OnTouchListener,
                calculateBoundsForPosition(isHorizontalDivision() ? mDisplayHeight : mDisplayWidth,
                        mDockSide, mDockedTaskRect);
            }

            // Move a docked app if from the right in position with the divider up to insets
            if (mDockSide == DOCKED_RIGHT) {
                mDockedTaskRect.offset(Math.max(position,
                        mStableInsets.left) - mDockedTaskRect.left, 0);
            }
            calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
                    mOtherTaskRect);
            mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
+12 −4
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT;
import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager
        .NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
@@ -178,6 +180,7 @@ import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
import com.android.systemui.recents.events.activity.UndockingTaskEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.ActivatableNotificationView;
@@ -207,14 +210,12 @@ import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -1339,8 +1340,15 @@ public class StatusBar extends SystemUI implements DemoMode,
        }
        int dockSide = WindowManagerProxy.getInstance().getDockSide();
        if (dockSide == WindowManager.DOCKED_INVALID) {
            return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
                    ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);
            final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition();
            if (navbarPos == NAV_BAR_POS_INVALID) {
                return false;
            }
            int createMode = navbarPos == NAV_BAR_POS_LEFT
                    ? ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
                    : ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
            return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE, createMode,
                    null, metricsDockAction);
        } else {
            Divider divider = getComponent(Divider.class);
            if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) {
+28 −6
Original line number Diff line number Diff line
@@ -234,6 +234,7 @@ import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IApplicationToken;
@@ -7191,14 +7192,35 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    }

    @Override
    public boolean isDockSideAllowed(int dockSide) {
    public boolean isDockSideAllowed(int dockSide, int originalDockSide, int displayWidth,
            int displayHeight, int displayRotation) {
        final int barPosition = navigationBarPosition(displayWidth, displayHeight, displayRotation);
        return isDockSideAllowed(dockSide, originalDockSide, barPosition, mNavigationBarCanMove);
    }

        // We do not allow all dock sides at which the navigation bar touches the docked stack.
        if (!mNavigationBarCanMove) {
            return dockSide == DOCKED_TOP || dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT;
        } else {
            return dockSide == DOCKED_TOP || dockSide == DOCKED_LEFT;
    @VisibleForTesting
    static boolean isDockSideAllowed(int dockSide, int originalDockSide,
            int navBarPosition, boolean navigationBarCanMove) {
        if (dockSide == DOCKED_TOP) {
            return true;
        }

        if (navigationBarCanMove) {
            // Only allow the dockside opposite to the nav bar position in landscape
            return dockSide == DOCKED_LEFT && navBarPosition == NAV_BAR_RIGHT
                    || dockSide == DOCKED_RIGHT && navBarPosition == NAV_BAR_LEFT;
        }

        // Side is the same as original side
        if (dockSide == originalDockSide) {
            return true;
        }

        // Only if original docked side was top in portrait will allow left for landscape
        if (dockSide == DOCKED_LEFT && originalDockSide == DOCKED_TOP) {
            return true;
        }
        return false;
    }

    void sendCloseSystemWindows() {
Loading