Loading services/core/java/com/android/server/am/ActivityStack.java +36 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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(); } Loading Loading @@ -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 Loading Loading @@ -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; } Loading Loading @@ -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; } Loading Loading @@ -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, Loading services/core/java/com/android/server/am/ActivityStackSupervisor.java +4 −11 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; } Loading Loading @@ -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 Loading Loading @@ -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(); } } Loading services/core/java/com/android/server/am/LaunchingTaskPositioner.java 0 → 100644 +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; } } services/core/java/com/android/server/am/TaskRecord.java +8 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading
services/core/java/com/android/server/am/ActivityStack.java +36 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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(); } Loading Loading @@ -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 Loading Loading @@ -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; } Loading Loading @@ -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; } Loading Loading @@ -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, Loading
services/core/java/com/android/server/am/ActivityStackSupervisor.java +4 −11 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; } Loading Loading @@ -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 Loading Loading @@ -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(); } } Loading
services/core/java/com/android/server/am/LaunchingTaskPositioner.java 0 → 100644 +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; } }
services/core/java/com/android/server/am/TaskRecord.java +8 −0 Original line number Diff line number Diff line Loading @@ -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); Loading