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

Commit b816b862 authored by Chong Zhang's avatar Chong Zhang
Browse files

Shift bottom stack upward and fold top stack when IME is visible

bug: 26293982
Change-Id: If5f22037e12edb6d67b80ff1deb1be7a028aa76c
parent c9fd313f
Loading
Loading
Loading
Loading
+102 −2
Original line number Diff line number Diff line
@@ -72,6 +72,12 @@ public class TaskStack implements DimLayer.DimLayerUser {
    /** Content limits relative to the DisplayContent this sits in. */
    private Rect mBounds = new Rect();

    /** Screen content area excluding IM windows, etc. */
    private final Rect mContentBounds = new Rect();

    /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
    private final Rect mAdjustedBounds = new Rect();

    /** Whether mBounds is fullscreen */
    private boolean mFullscreen = true;

@@ -162,6 +168,85 @@ public class TaskStack implements DimLayer.DimLayerUser {
        return mTmpRect.equals(bounds);
    }

    void alignTasksToAdjustedBounds(final Rect adjustedBounds) {
        if (mFullscreen) {
            return;
        }
        // Update bounds of containing tasks.
        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
            final Task task = mTasks.get(taskNdx);
            if (task.isTwoFingerScrollMode()) {
                // If we're scrolling we don't care about your bounds or configs,
                // they should be null as if we were in fullscreen.
                task.resizeLocked(null, null, false /* forced */);
                task.getBounds(mTmpRect2);
                task.scrollLocked(mTmpRect2);
            } else if (task.isResizeable()) {
                task.getBounds(mTmpRect2);
                mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
                task.resizeLocked(mTmpRect2, task.mOverrideConfig, false /* forced */);
            }
        }
    }

    void adjustForIME(final WindowState imeWin) {
        final int dockedSide = getDockSide();
        final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
        final Rect adjustedBounds = mAdjustedBounds;
        if (imeWin == null || !dockedTopOrBottom) {
            // If mContentBounds is already empty, it means we're not applying
            // any adjustments, so nothing to do; otherwise clear any adjustments.
            if (!mContentBounds.isEmpty()) {
                mContentBounds.setEmpty();
                adjustedBounds.set(mBounds);
                alignTasksToAdjustedBounds(adjustedBounds);
            }
            return;
        }

        final Rect displayContentRect = mTmpRect;
        final Rect contentBounds = mTmpRect2;

        // Calculate the content bounds excluding the area occupied by IME
        mDisplayContent.getContentRect(displayContentRect);
        contentBounds.set(displayContentRect);
        int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
        imeTop += imeWin.getGivenContentInsetsLw().top;
        if (contentBounds.bottom > imeTop) {
            contentBounds.bottom = imeTop;
        }

        // If content bounds not changing, nothing to do.
        if (mContentBounds.equals(contentBounds)) {
            return;
        }

        // Content bounds changed, need to apply adjustments depending on dock sides.
        mContentBounds.set(contentBounds);
        adjustedBounds.set(mBounds);
        final int yOffset = displayContentRect.bottom - contentBounds.bottom;

        if (dockedSide == DOCKED_TOP) {
            // If this stack is docked on top, we make it smaller so the bottom stack is not
            // occluded by IME. We shift its bottom up by the height of the IME (capped by
            // the display content rect). Note that we don't change the task bounds.
            adjustedBounds.bottom = Math.max(
                    adjustedBounds.bottom - yOffset, displayContentRect.top);
        } else {
            // If this stack is docked on bottom, we shift it up so that it's not occluded by
            // IME. We try to move it up by the height of the IME window (although the best
            // we could do is to make the top stack fully collapsed).
            final int dividerWidth = mDisplayContent.mDividerControllerLocked.getContentWidth();
            adjustedBounds.top = Math.max(
                    adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth);
            adjustedBounds.bottom = adjustedBounds.top + mBounds.height();

            // We also move the member tasks together, taking care not to resize them.
            // Resizing might cause relaunch, and IME window may not come back after that.
            alignTasksToAdjustedBounds(adjustedBounds);
        }
    }

    private boolean setBounds(Rect bounds) {
        boolean oldFullscreen = mFullscreen;
        int rotation = Surface.ROTATION_0;
@@ -191,6 +276,16 @@ public class TaskStack implements DimLayer.DimLayerUser {

        mBounds.set(bounds);
        mRotation = rotation;

        // Clear the adjusted content bounds as they're no longer valid.
        // If IME is still visible, these will be re-applied.
        // Note that we don't clear mContentBounds here, so that we know the last IME
        // adjust we applied.
        // If user starts dragging the dock divider while IME is visible, the new bounds
        // we received are based on the actual screen location of the divider. It already
        // accounted for the IME window, so we don't want to adjust again.
        mAdjustedBounds.set(mBounds);

        return true;
    }

@@ -215,9 +310,14 @@ public class TaskStack implements DimLayer.DimLayerUser {

    public void getBounds(Rect out) {
        if (useCurrentBounds()) {
            // No need to adjust the output bounds if fullscreen or the docked stack is visible
            // If we're currently adjusting for IME, we use the adjusted bounds; otherwise,
            // no need to adjust the output bounds if fullscreen or the docked stack is visible
            // since it is already what we want to represent to the rest of the system.
            if (!mContentBounds.isEmpty()) {
                out.set(mAdjustedBounds);
            } else {
                out.set(mBounds);
            }
            return;
        }

+24 −2
Original line number Diff line number Diff line
@@ -160,6 +160,7 @@ import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
@@ -8048,8 +8049,29 @@ public class WindowManagerService extends IWindowManager.Stub
                }
                case UPDATE_DOCKED_STACK_DIVIDER: {
                    synchronized (mWindowMap) {
                        getDefaultDisplayContentLocked().getDockedDividerController()
                                .reevaluateVisibility(false);
                        final DisplayContent displayContent = getDefaultDisplayContentLocked();

                        displayContent.getDockedDividerController().reevaluateVisibility(false);

                        final WindowState imeWin = mInputMethodWindow;
                        final TaskStack focusedStack =
                                mCurrentFocus != null ? mCurrentFocus.getStack() : null;
                        if (imeWin != null && focusedStack != null && imeWin.isVisibleNow()
                                && focusedStack.getDockSide() == DOCKED_BOTTOM){
                            final ArrayList<TaskStack> stacks = displayContent.getStacks();
                            for (int i = stacks.size() - 1; i >= 0; --i) {
                                final TaskStack stack = stacks.get(i);
                                if (stack.isVisibleLocked()) {
                                    stack.adjustForIME(imeWin);
                                }
                            }
                        } else {
                            final ArrayList<TaskStack> stacks = displayContent.getStacks();
                            for (int i = stacks.size() - 1; i >= 0; --i) {
                                final TaskStack stack = stacks.get(i);
                                stack.adjustForIME(null);
                            }
                        }
                    }
                }
                break;