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

Commit 8dc911ae authored by Filip Gruszczynski's avatar Filip Gruszczynski Committed by Android (Google) Code Review
Browse files

Merge "Non colliding positioning of entering resizeable tasks."

parents b03198de e5390e73
Loading
Loading
Loading
Loading
+36 −4
Original line number Diff line number Diff line
@@ -248,6 +248,8 @@ final class ActivityStack {
    /** Run all ActivityStacks through this */
    final ActivityStackSupervisor mStackSupervisor;

    private final LaunchingTaskPositioner mTaskPositioner;

    static final int PAUSE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 1;
    static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 2;
    static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 3;
@@ -363,6 +365,33 @@ final class ActivityStack {
        mStackId = activityContainer.mStackId;
        mCurrentUser = mService.mCurrentUserId;
        mRecentTasks = recentTasks;
        mTaskPositioner = mStackId == FREEFORM_WORKSPACE_STACK_ID
                ? new LaunchingTaskPositioner() : null;
    }

    void attachDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay, boolean onTop) {
        mDisplayId = activityDisplay.mDisplayId;
        mStacks = activityDisplay.mStacks;
        mBounds = mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId, onTop);
        mFullscreen = mBounds == null;
        if (mTaskPositioner != null) {
            mTaskPositioner.setDisplay(activityDisplay.mDisplay);
            mTaskPositioner.configure(mBounds);
        }
    }

    void detachDisplay() {
        mDisplayId = Display.INVALID_DISPLAY;
        mStacks = null;
        if (mTaskPositioner != null) {
            mTaskPositioner.reset();
        }
        mWindowManager.detachStack(mStackId);
    }

    void setBounds(Rect bounds) {
        mBounds = mFullscreen ? null : new Rect(bounds);
        mTaskPositioner.configure(bounds);
    }

    boolean okToShowLocked(ActivityRecord r) {
@@ -2223,7 +2252,7 @@ final class ActivityStack {
                                + task, new RuntimeException("here").fillInStackTrace());
                        task.addActivityToTop(r);
                        r.putInHistory();
                        addAppToken(r, task);
                        addConfigOverride(r, task);
                        if (VALIDATE_TOKENS) {
                            validateAppTokensLocked();
                        }
@@ -2283,7 +2312,7 @@ final class ActivityStack {
                        : AppTransition.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
                mNoAnimActivities.remove(r);
            }
            addAppToken(r, task);
            addConfigOverride(r, task);
            boolean doShow = true;
            if (newTask) {
                // Even though this activity is starting fresh, we still need
@@ -2332,7 +2361,7 @@ final class ActivityStack {
        } else {
            // If this is the first activity, don't do any fancy animations,
            // because there is nothing for it to animate on top of.
            addAppToken(r, task);
            addConfigOverride(r, task);
            ActivityOptions.abort(options);
            options = null;
        }
@@ -4513,6 +4542,9 @@ final class ActivityStack {
            boolean toTop) {
        TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
                voiceInteractor);
        if (mTaskPositioner != null) {
            mTaskPositioner.updateDefaultBounds(task, mTaskHistory);
        }
        addTask(task, toTop, false);
        return task;
    }
@@ -4548,7 +4580,7 @@ final class ActivityStack {
        }
    }

    void addAppToken(ActivityRecord r, TaskRecord task) {
    void addConfigOverride(ActivityRecord r, TaskRecord task) {
        final Rect bounds = task.getLaunchBounds();
        final Configuration config =
                mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
+4 −11
Original line number Diff line number Diff line
@@ -2977,7 +2977,7 @@ public final class ActivityStackSupervisor implements DisplayListener {

            }
        }
        stack.mBounds = stack.mFullscreen ? null : new Rect(bounds);
        stack.setBounds(bounds);

        if (r != null) {
            final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
@@ -3112,7 +3112,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
                "Added restored task=" + task + " to stack=" + stack);
        final ArrayList<ActivityRecord> activities = task.mActivities;
        for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
            stack.addAppToken(activities.get(activityNdx), task);
            stack.addConfigOverride(activities.get(activityNdx), task);
        }
        return true;
    }
@@ -4387,13 +4387,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
            if (DEBUG_STACK) Slog.d(TAG_STACK, "attachToDisplayLocked: " + this
                    + " to display=" + activityDisplay + " onTop=" + onTop);
            mActivityDisplay = activityDisplay;
            mStack.mDisplayId = activityDisplay.mDisplayId;
            mStack.mStacks = activityDisplay.mStacks;

            mStack.attachDisplay(activityDisplay, onTop);
            activityDisplay.attachActivities(mStack, onTop);
            mStack.mBounds =
                    mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId, onTop);
            mStack.mFullscreen = mStack.mBounds == null;
        }

        @Override
@@ -4465,9 +4460,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
            if (mActivityDisplay != null) {
                mActivityDisplay.detachActivitiesLocked(mStack);
                mActivityDisplay = null;
                mStack.mDisplayId = -1;
                mStack.mStacks = null;
                mWindowManager.detachStack(mStackId);
                mStack.detachDisplay();
            }
        }

+142 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.am;

import android.graphics.Point;
import android.graphics.Rect;
import android.view.Display;

import java.util.ArrayList;

/**
 * Determines where a launching task should be positioned and sized on the display.
 */
class LaunchingTaskPositioner {
    // Determines how close window frames/corners have to be to call them colliding.
    private static final int BOUNDS_CONFLICT_MIN_DISTANCE = 4;

    // Task will receive dimensions based on available dimensions divided by this.
    private static final int WINDOW_SIZE_DENOMINATOR = 2;

    // Task will receive margins based on available dimensions divided by this.
    private static final int MARGIN_SIZE_DENOMINATOR = 4;

    // If task bounds collide with some other, we will step and try again until we find a good
    // position. The step will be determined by using dimensions and dividing it by this.
    private static final int STEP_DENOMINATOR = 16;

    // We always want to step by at least this.
    private static final int MINIMAL_STEP = 1;

    private boolean mDefaultStartBoundsConfigurationSet = false;
    private final Rect mAvailableRect = new Rect();
    private int mDefaultFreeformStartX;
    private int mDefaultFreeformStartY;
    private int mDefaultFreeformWidth;
    private int mDefaultFreeformHeight;
    private int mDefaultFreeformStepHorizontal;
    private int mDefaultFreeformStepVertical;
    private int mDisplayWidth;
    private int mDisplayHeight;

    void setDisplay(Display display) {
        Point size = new Point();
        display.getSize(size);
        mDisplayWidth = size.x;
        mDisplayHeight = size.y;
    }

    void configure(Rect stackBounds) {
        if (stackBounds == null) {
            mAvailableRect.set(0, 0, mDisplayWidth, mDisplayHeight);
        } else {
            mAvailableRect.set(stackBounds);
        }
        int width = mAvailableRect.width();
        int height = mAvailableRect.height();
        mDefaultFreeformStartX = mAvailableRect.left + width / MARGIN_SIZE_DENOMINATOR;
        mDefaultFreeformStartY = mAvailableRect.top + height / MARGIN_SIZE_DENOMINATOR;
        mDefaultFreeformWidth = width / WINDOW_SIZE_DENOMINATOR;
        mDefaultFreeformHeight = height / WINDOW_SIZE_DENOMINATOR;
        mDefaultFreeformStepHorizontal = Math.max(width / STEP_DENOMINATOR, MINIMAL_STEP);
        mDefaultFreeformStepVertical = Math.max(height / STEP_DENOMINATOR, MINIMAL_STEP);
        mDefaultStartBoundsConfigurationSet = true;
    }

    /**
     * Tries to set task's bound in a way that it won't collide with any other task. By colliding
     * we mean that two tasks have left-top corner very close to each other, so one might get
     * obfuscated by the other one.
     *
     * @param task Task for which we want to find bounds that won't collide with other.
     * @param tasks Existing tasks with which we don't want to collide.
     */
    void updateDefaultBounds(TaskRecord task, ArrayList<TaskRecord> tasks) {
        if (!mDefaultStartBoundsConfigurationSet) {
            return;
        }
        int startX = mDefaultFreeformStartX;
        int startY = mDefaultFreeformStartY;
        final int right = mAvailableRect.right;
        final int bottom = mAvailableRect.bottom;
        boolean restarted = false;
        while (boundsConflict(startX, startY, tasks)) {
            // Unfortunately there is already a task at that spot, so we need to look for some
            // other place.
            startX += mDefaultFreeformStepHorizontal;
            startY += mDefaultFreeformStepVertical;
            if (startX + mDefaultFreeformWidth > right
                    || startY + mDefaultFreeformHeight > bottom) {
                // We don't want the task to go outside of the display, because it won't look
                // nice. Let's restart from the top instead, because there should be some space
                // there.
                startX = mAvailableRect.left;
                startY = mAvailableRect.top;
                restarted = true;
            }
            if (restarted
                    && (startX > mDefaultFreeformStartX || startY > mDefaultFreeformStartY)) {
                // If we restarted and crossed the initial position, let's not struggle anymore.
                // The user already must have ton of tasks visible, we can just smack the new
                // one in the center.
                startX = mDefaultFreeformStartX;
                startY = mDefaultFreeformStartY;
                break;
            }
        }
        task.setInitialBounds(startX, startY, startX + mDefaultFreeformWidth,
                startY + mDefaultFreeformHeight);
    }

    private boolean boundsConflict(int startX, int startY, ArrayList<TaskRecord> tasks) {
        for (int i = tasks.size() - 1; i >= 0; i--) {
            TaskRecord task = tasks.get(i);
            if (!task.mActivities.isEmpty()) {
                Rect bounds = task.mBounds;
                if (bounds != null && (Math.abs(bounds.left - startX) < BOUNDS_CONFLICT_MIN_DISTANCE
                        || Math.abs(bounds.top - startY) < BOUNDS_CONFLICT_MIN_DISTANCE)) {
                    return true;
                }
            }
        }
        return false;
    }

    void reset() {
        mDefaultStartBoundsConfigurationSet = false;
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -1217,6 +1217,14 @@ final class TaskRecord {
        return mLastNonFullscreenBounds;
    }

    void setInitialBounds(int left, int top, int right, int bottom) {
        if (mBounds == null) {
            mBounds = new Rect();
        }
        mBounds.set(left, top, right, bottom);
        mLastNonFullscreenBounds = mBounds;
    }

    void dump(PrintWriter pw, String prefix) {
        pw.print(prefix); pw.print("userId="); pw.print(userId);
                pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);