Files
frameworks_base/services/java/com/android/server/wm/TaskStack.java
Craig Mautner f0ac5c87f2 Fix unnecessary and harmful task movement.
Changing the focus to a new activity should not move it to the top of
the task stack. When the previous activity fully pauses and the new
focused activity resumes then it will be brought to the top of the
task stack at the proper time. Moving it there prematurely causes the
ActivityManager and WindowManager stack sequences to be out of sync.

Fixes bug 9518153.

Also remove false warnings in validateTopActivitiesLocked() and add
debug for task movement to TaskStack.

Change-Id: Ib57500b07ded97223155cda7ef603aecc9b642c3
2013-06-24 11:29:09 -07:00

276 lines
9.9 KiB
Java

/*
* Copyright (C) 2013 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.wm;
import static com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerService.TAG;
import android.graphics.Rect;
import android.os.Debug;
import android.util.Slog;
import android.util.TypedValue;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
import java.io.PrintWriter;
import java.util.ArrayList;
public class TaskStack {
/** Amount of time in milliseconds to animate the dim surface from one value to another,
* when no window animation is driving it. */
private static final int DEFAULT_DIM_DURATION = 200;
/** Unique identifier */
final int mStackId;
/** The service */
private final WindowManagerService mService;
/** The display this stack sits under. */
private final DisplayContent mDisplayContent;
/** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
* mTaskHistory in the ActivityStack with the same mStackId */
private ArrayList<Task> mTasks = new ArrayList<Task>();
/** The StackBox this sits in. */
StackBox mStackBox;
/** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */
final DimLayer mDimLayer;
/** The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. */
WindowStateAnimator mDimWinAnimator;
/** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
final DimLayer mAnimationBackgroundSurface;
/** The particular window with an Animation with non-zero background color. */
WindowStateAnimator mAnimationBackgroundAnimator;
/** Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the end
* then stop any dimming. */
boolean mDimmingTag;
TaskStack(WindowManagerService service, int stackId, DisplayContent displayContent) {
mService = service;
mStackId = stackId;
mDisplayContent = displayContent;
final int displayId = displayContent.getDisplayId();
mDimLayer = new DimLayer(service, displayId);
mAnimationBackgroundSurface = new DimLayer(service, displayId);
}
DisplayContent getDisplayContent() {
return mDisplayContent;
}
ArrayList<Task> getTasks() {
return mTasks;
}
boolean isHomeStack() {
return mStackId == HOME_STACK_ID;
}
/**
* Put a Task in this stack. Used for adding and moving.
* @param task The task to add.
* @param toTop Whether to add it to the top or bottom.
*/
boolean addTask(Task task, boolean toTop) {
if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "addTask: task=" + task + " toTop=" + toTop);
mStackBox.makeDirty();
mTasks.add(toTop ? mTasks.size() : 0, task);
task.mStack = this;
return mDisplayContent.moveHomeStackBox(mStackId == HOME_STACK_ID);
}
boolean moveTaskToTop(Task task) {
if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToTop: task=" + task + " Callers="
+ Debug.getCallers(6));
mTasks.remove(task);
return addTask(task, true);
}
boolean moveTaskToBottom(Task task) {
if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToBottom: task=" + task);
mTasks.remove(task);
return addTask(task, false);
}
/**
* Delete a Task from this stack. If it is the last Task in the stack, remove this stack from
* its parent StackBox and merge the parent.
* @param task The Task to delete.
*/
void removeTask(Task task) {
if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task);
mStackBox.makeDirty();
mTasks.remove(task);
}
int remove() {
mAnimationBackgroundSurface.destroySurface();
mDimLayer.destroySurface();
return mStackBox.remove();
}
void resetAnimationBackgroundAnimator() {
mAnimationBackgroundAnimator = null;
mAnimationBackgroundSurface.hide();
}
private long getDimBehindFadeDuration(long duration) {
TypedValue tv = new TypedValue();
mService.mContext.getResources().getValue(
com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true);
if (tv.type == TypedValue.TYPE_FRACTION) {
duration = (long)tv.getFraction(duration, duration);
} else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) {
duration = tv.data;
}
return duration;
}
boolean animateDimLayers() {
final int dimLayer;
final float dimAmount;
if (mDimWinAnimator == null) {
dimLayer = mDimLayer.getLayer();
dimAmount = 0;
} else {
dimLayer = mDimWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM;
dimAmount = mDimWinAnimator.mWin.mAttrs.dimAmount;
}
final float targetAlpha = mDimLayer.getTargetAlpha();
if (targetAlpha != dimAmount) {
if (mDimWinAnimator == null) {
mDimLayer.hide(DEFAULT_DIM_DURATION);
} else {
long duration = (mDimWinAnimator.mAnimating && mDimWinAnimator.mAnimation != null)
? mDimWinAnimator.mAnimation.computeDurationHint()
: DEFAULT_DIM_DURATION;
if (targetAlpha > dimAmount) {
duration = getDimBehindFadeDuration(duration);
}
mDimLayer.show(dimLayer, dimAmount, duration);
}
} else if (mDimLayer.getLayer() != dimLayer) {
mDimLayer.setLayer(dimLayer);
}
if (mDimLayer.isAnimating()) {
if (!mService.okToDisplay()) {
// Jump to the end of the animation.
mDimLayer.show();
} else {
return mDimLayer.stepAnimation();
}
}
return false;
}
void resetDimmingTag() {
mDimmingTag = false;
}
void setDimmingTag() {
mDimmingTag = true;
}
boolean testDimmingTag() {
return mDimmingTag;
}
boolean isDimming() {
return mDimLayer.isDimming();
}
boolean isDimming(WindowStateAnimator winAnimator) {
return mDimWinAnimator == winAnimator && mDimLayer.isDimming();
}
void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) {
// Only set dim params on the highest dimmed layer.
final WindowStateAnimator existingDimWinAnimator = mDimWinAnimator;
// Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
if (newWinAnimator.mSurfaceShown && (existingDimWinAnimator == null
|| !existingDimWinAnimator.mSurfaceShown
|| existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
mDimWinAnimator = newWinAnimator;
}
}
void stopDimmingIfNeeded() {
if (!mDimmingTag && isDimming()) {
mDimWinAnimator = null;
}
}
void setAnimationBackground(WindowStateAnimator winAnimator, int color) {
int animLayer = winAnimator.mAnimLayer;
if (mAnimationBackgroundAnimator == null
|| animLayer < mAnimationBackgroundAnimator.mAnimLayer) {
mAnimationBackgroundAnimator = winAnimator;
animLayer = mService.adjustAnimationBackground(winAnimator);
mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM,
((color >> 24) & 0xff) / 255f, 0);
}
}
void setBounds(Rect bounds, boolean underStatusBar) {
mDimLayer.setBounds(bounds);
mAnimationBackgroundSurface.setBounds(bounds);
final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState win = windows.get(winNdx);
if (!resizingWindows.contains(win)) {
resizingWindows.add(win);
}
win.mUnderStatusBar = underStatusBar;
}
}
}
}
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
pw.print(prefix); pw.println(mTasks.get(taskNdx));
}
if (mAnimationBackgroundSurface.isDimming()) {
pw.print(prefix); pw.println("mWindowAnimationBackgroundSurface:");
mAnimationBackgroundSurface.printTo(prefix + " ", pw);
}
if (mDimLayer.isDimming()) {
pw.print(prefix); pw.println("mDimLayer:");
mDimLayer.printTo(prefix, pw);
pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator);
}
}
@Override
public String toString() {
return "{stackId=" + mStackId + " tasks=" + mTasks + "}";
}
}