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