Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.wm;
     18 
     19 import static com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT;
     20 import static com.android.server.wm.WindowManagerService.TAG;
     21 
     22 import android.graphics.Rect;
     23 import android.os.Debug;
     24 import android.util.Slog;
     25 import android.util.TypedValue;
     26 
     27 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
     28 
     29 import java.io.PrintWriter;
     30 import java.util.ArrayList;
     31 
     32 public class TaskStack {
     33     /** Amount of time in milliseconds to animate the dim surface from one value to another,
     34      * when no window animation is driving it. */
     35     private static final int DEFAULT_DIM_DURATION = 200;
     36 
     37     /** Unique identifier */
     38     final int mStackId;
     39 
     40     /** The service */
     41     private final WindowManagerService mService;
     42 
     43     /** The display this stack sits under. */
     44     private final DisplayContent mDisplayContent;
     45 
     46     /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
     47      * mTaskHistory in the ActivityStack with the same mStackId */
     48     private ArrayList<Task> mTasks = new ArrayList<Task>();
     49 
     50     /** The StackBox this sits in. */
     51     StackBox mStackBox;
     52 
     53     /** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */
     54     final DimLayer mDimLayer;
     55 
     56     /** The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. */
     57     WindowStateAnimator mDimWinAnimator;
     58 
     59     /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
     60     final DimLayer mAnimationBackgroundSurface;
     61 
     62     /** The particular window with an Animation with non-zero background color. */
     63     WindowStateAnimator mAnimationBackgroundAnimator;
     64 
     65     /** Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the end
     66      * then stop any dimming. */
     67     boolean mDimmingTag;
     68 
     69     TaskStack(WindowManagerService service, int stackId, DisplayContent displayContent) {
     70         mService = service;
     71         mStackId = stackId;
     72         mDisplayContent = displayContent;
     73         final int displayId = displayContent.getDisplayId();
     74         mDimLayer = new DimLayer(service, this);
     75         mAnimationBackgroundSurface = new DimLayer(service, this);
     76     }
     77 
     78     DisplayContent getDisplayContent() {
     79         return mDisplayContent;
     80     }
     81 
     82     ArrayList<Task> getTasks() {
     83         return mTasks;
     84     }
     85 
     86     boolean isHomeStack() {
     87         return mStackId == HOME_STACK_ID;
     88     }
     89 
     90     boolean hasSibling() {
     91         return mStackBox.mParent != null;
     92     }
     93 
     94     /**
     95      * Put a Task in this stack. Used for adding and moving.
     96      * @param task The task to add.
     97      * @param toTop Whether to add it to the top or bottom.
     98      */
     99     boolean addTask(Task task, boolean toTop) {
    100         mStackBox.makeDirty();
    101 
    102         int stackNdx;
    103         if (!toTop) {
    104             stackNdx = 0;
    105         } else {
    106             stackNdx = mTasks.size();
    107             final int currentUserId = mService.mCurrentUserId;
    108             if (task.mUserId != currentUserId) {
    109                 // Place the task below all current user tasks.
    110                 while (--stackNdx >= 0) {
    111                     if (currentUserId != mTasks.get(stackNdx).mUserId) {
    112                         break;
    113                     }
    114                 }
    115                 ++stackNdx;
    116             }
    117         }
    118         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "addTask: task=" + task + " toTop=" + toTop
    119                 + " pos=" + stackNdx);
    120         mTasks.add(stackNdx, task);
    121 
    122         task.mStack = this;
    123         return mDisplayContent.moveHomeStackBox(mStackId == HOME_STACK_ID);
    124     }
    125 
    126     boolean moveTaskToTop(Task task) {
    127         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToTop: task=" + task + " Callers="
    128                 + Debug.getCallers(6));
    129         mTasks.remove(task);
    130         return addTask(task, true);
    131     }
    132 
    133     boolean moveTaskToBottom(Task task) {
    134         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToBottom: task=" + task);
    135         mTasks.remove(task);
    136         return addTask(task, false);
    137     }
    138 
    139     /**
    140      * Delete a Task from this stack. If it is the last Task in the stack, remove this stack from
    141      * its parent StackBox and merge the parent.
    142      * @param task The Task to delete.
    143      */
    144     void removeTask(Task task) {
    145         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task);
    146         mStackBox.makeDirty();
    147         mTasks.remove(task);
    148     }
    149 
    150     int remove() {
    151         mAnimationBackgroundSurface.destroySurface();
    152         mDimLayer.destroySurface();
    153         return mStackBox.remove();
    154     }
    155 
    156     void resetAnimationBackgroundAnimator() {
    157         mAnimationBackgroundAnimator = null;
    158         mAnimationBackgroundSurface.hide();
    159     }
    160 
    161     private long getDimBehindFadeDuration(long duration) {
    162         TypedValue tv = new TypedValue();
    163         mService.mContext.getResources().getValue(
    164                 com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true);
    165         if (tv.type == TypedValue.TYPE_FRACTION) {
    166             duration = (long)tv.getFraction(duration, duration);
    167         } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) {
    168             duration = tv.data;
    169         }
    170         return duration;
    171     }
    172 
    173     boolean animateDimLayers() {
    174         final int dimLayer;
    175         final float dimAmount;
    176         if (mDimWinAnimator == null) {
    177             dimLayer = mDimLayer.getLayer();
    178             dimAmount = 0;
    179         } else {
    180             dimLayer = mDimWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM;
    181             dimAmount = mDimWinAnimator.mWin.mAttrs.dimAmount;
    182         }
    183         final float targetAlpha = mDimLayer.getTargetAlpha();
    184         if (targetAlpha != dimAmount) {
    185             if (mDimWinAnimator == null) {
    186                 mDimLayer.hide(DEFAULT_DIM_DURATION);
    187             } else {
    188                 long duration = (mDimWinAnimator.mAnimating && mDimWinAnimator.mAnimation != null)
    189                         ? mDimWinAnimator.mAnimation.computeDurationHint()
    190                         : DEFAULT_DIM_DURATION;
    191                 if (targetAlpha > dimAmount) {
    192                     duration = getDimBehindFadeDuration(duration);
    193                 }
    194                 mDimLayer.show(dimLayer, dimAmount, duration);
    195             }
    196         } else if (mDimLayer.getLayer() != dimLayer) {
    197             mDimLayer.setLayer(dimLayer);
    198         }
    199         if (mDimLayer.isAnimating()) {
    200             if (!mService.okToDisplay()) {
    201                 // Jump to the end of the animation.
    202                 mDimLayer.show();
    203             } else {
    204                 return mDimLayer.stepAnimation();
    205             }
    206         }
    207         return false;
    208     }
    209 
    210     void resetDimmingTag() {
    211         mDimmingTag = false;
    212     }
    213 
    214     void setDimmingTag() {
    215         mDimmingTag = true;
    216     }
    217 
    218     boolean testDimmingTag() {
    219         return mDimmingTag;
    220     }
    221 
    222     boolean isDimming() {
    223         return mDimLayer.isDimming();
    224     }
    225 
    226     boolean isDimming(WindowStateAnimator winAnimator) {
    227         return mDimWinAnimator == winAnimator && mDimLayer.isDimming();
    228     }
    229 
    230     void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) {
    231         // Only set dim params on the highest dimmed layer.
    232         final WindowStateAnimator existingDimWinAnimator = mDimWinAnimator;
    233         // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
    234         if (newWinAnimator.mSurfaceShown && (existingDimWinAnimator == null
    235                 || !existingDimWinAnimator.mSurfaceShown
    236                 || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
    237             mDimWinAnimator = newWinAnimator;
    238         }
    239     }
    240 
    241     void stopDimmingIfNeeded() {
    242         if (!mDimmingTag && isDimming()) {
    243             mDimWinAnimator = null;
    244         }
    245     }
    246 
    247     void setAnimationBackground(WindowStateAnimator winAnimator, int color) {
    248         int animLayer = winAnimator.mAnimLayer;
    249         if (mAnimationBackgroundAnimator == null
    250                 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) {
    251             mAnimationBackgroundAnimator = winAnimator;
    252             animLayer = mService.adjustAnimationBackground(winAnimator);
    253             mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM,
    254                     ((color >> 24) & 0xff) / 255f, 0);
    255         }
    256     }
    257 
    258     void setBounds(Rect bounds, boolean underStatusBar) {
    259         mDimLayer.setBounds(bounds);
    260         mAnimationBackgroundSurface.setBounds(bounds);
    261 
    262         final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
    263         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
    264             final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
    265             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
    266                 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
    267                 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
    268                     final WindowState win = windows.get(winNdx);
    269                     if (!resizingWindows.contains(win)) {
    270                         resizingWindows.add(win);
    271                     }
    272                     win.mUnderStatusBar = underStatusBar;
    273                 }
    274             }
    275         }
    276     }
    277 
    278     void switchUser(int userId) {
    279         int top = mTasks.size();
    280         for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
    281             Task task = mTasks.get(taskNdx);
    282             if (task.mUserId == userId) {
    283                 mTasks.remove(taskNdx);
    284                 mTasks.add(task);
    285                 --top;
    286             }
    287         }
    288     }
    289 
    290     public void dump(String prefix, PrintWriter pw) {
    291         pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
    292         for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
    293             pw.print(prefix); pw.println(mTasks.get(taskNdx));
    294         }
    295         if (mAnimationBackgroundSurface.isDimming()) {
    296             pw.print(prefix); pw.println("mWindowAnimationBackgroundSurface:");
    297             mAnimationBackgroundSurface.printTo(prefix + "  ", pw);
    298         }
    299         if (mDimLayer.isDimming()) {
    300             pw.print(prefix); pw.println("mDimLayer:");
    301             mDimLayer.printTo(prefix, pw);
    302             pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator);
    303         }
    304     }
    305 
    306     @Override
    307     public String toString() {
    308         return "{stackId=" + mStackId + " tasks=" + mTasks + "}";
    309     }
    310 }
    311