Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2014 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 android.view.Display.DEFAULT_DISPLAY;
     20 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
     21 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
     22 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
     23 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     24 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
     25 import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
     26 
     27 import android.content.Context;
     28 import android.os.Trace;
     29 import android.util.Slog;
     30 import android.util.SparseArray;
     31 import android.util.TimeUtils;
     32 import android.view.Choreographer;
     33 import android.view.SurfaceControl;
     34 
     35 import com.android.server.AnimationThread;
     36 import com.android.server.policy.WindowManagerPolicy;
     37 
     38 import java.io.PrintWriter;
     39 import java.util.ArrayList;
     40 
     41 /**
     42  * Singleton class that carries out the animations and Surface operations in a separate task
     43  * on behalf of WindowManagerService.
     44  */
     45 public class WindowAnimator {
     46     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowAnimator" : TAG_WM;
     47 
     48     final WindowManagerService mService;
     49     final Context mContext;
     50     final WindowManagerPolicy mPolicy;
     51 
     52     /** Is any window animating? */
     53     private boolean mAnimating;
     54     private boolean mLastRootAnimating;
     55 
     56     final Choreographer.FrameCallback mAnimationFrameCallback;
     57 
     58     /** Time of current animation step. Reset on each iteration */
     59     long mCurrentTime;
     60 
     61     boolean mAppWindowAnimating;
     62     /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
     63      * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
     64     int mAnimTransactionSequence;
     65 
     66     /** Window currently running an animation that has requested it be detached
     67      * from the wallpaper.  This means we need to ensure the wallpaper is
     68      * visible behind it in case it animates in a way that would allow it to be
     69      * seen. If multiple windows satisfy this, use the lowest window. */
     70     WindowState mWindowDetachedWallpaper = null;
     71 
     72     int mBulkUpdateParams = 0;
     73     Object mLastWindowFreezeSource;
     74 
     75     SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = new SparseArray<>(2);
     76 
     77     private boolean mInitialized = false;
     78 
     79     // When set to true the animator will go over all windows after an animation frame is posted and
     80     // check if some got replaced and can be removed.
     81     private boolean mRemoveReplacedWindows = false;
     82 
     83     private Choreographer mChoreographer;
     84 
     85     /**
     86      * Indicates whether we have an animation frame callback scheduled, which will happen at
     87      * vsync-app and then schedule the animation tick at the right time (vsync-sf).
     88      */
     89     private boolean mAnimationFrameCallbackScheduled;
     90 
     91     /**
     92      * A list of runnable that need to be run after {@link WindowContainer#prepareSurfaces} is
     93      * executed and the corresponding transaction is closed and applied.
     94      */
     95     private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
     96     private boolean mInExecuteAfterPrepareSurfacesRunnables;
     97 
     98     private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
     99 
    100     WindowAnimator(final WindowManagerService service) {
    101         mService = service;
    102         mContext = service.mContext;
    103         mPolicy = service.mPolicy;
    104         AnimationThread.getHandler().runWithScissors(
    105                 () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */);
    106 
    107         mAnimationFrameCallback = frameTimeNs -> {
    108             synchronized (mService.mWindowMap) {
    109                 mAnimationFrameCallbackScheduled = false;
    110             }
    111             animate(frameTimeNs);
    112         };
    113     }
    114 
    115     void addDisplayLocked(final int displayId) {
    116         // Create the DisplayContentsAnimator object by retrieving it if the associated
    117         // {@link DisplayContent} exists.
    118         getDisplayContentsAnimatorLocked(displayId);
    119         if (displayId == DEFAULT_DISPLAY) {
    120             mInitialized = true;
    121         }
    122     }
    123 
    124     void removeDisplayLocked(final int displayId) {
    125         final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
    126         if (displayAnimator != null) {
    127             if (displayAnimator.mScreenRotationAnimation != null) {
    128                 displayAnimator.mScreenRotationAnimation.kill();
    129                 displayAnimator.mScreenRotationAnimation = null;
    130             }
    131         }
    132 
    133         mDisplayContentsAnimators.delete(displayId);
    134     }
    135 
    136     /**
    137      * DO NOT HOLD THE WINDOW MANAGER LOCK WHILE CALLING THIS METHOD. Reason: the method closes
    138      * an animation transaction, that might be blocking until the next sf-vsync, so we want to make
    139      * sure other threads can make progress if this happens.
    140      */
    141     private void animate(long frameTimeNs) {
    142 
    143         synchronized (mService.mWindowMap) {
    144             if (!mInitialized) {
    145                 return;
    146             }
    147 
    148             // Schedule next frame already such that back-pressure happens continuously
    149             scheduleAnimation();
    150         }
    151 
    152         synchronized (mService.mWindowMap) {
    153             mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
    154             mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
    155             mAnimating = false;
    156             if (DEBUG_WINDOW_TRACE) {
    157                 Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
    158             }
    159 
    160             if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animate");
    161             mService.openSurfaceTransaction();
    162             try {
    163                 final AccessibilityController accessibilityController =
    164                         mService.mAccessibilityController;
    165                 final int numDisplays = mDisplayContentsAnimators.size();
    166                 for (int i = 0; i < numDisplays; i++) {
    167                     final int displayId = mDisplayContentsAnimators.keyAt(i);
    168                     final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
    169                     DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
    170 
    171                     final ScreenRotationAnimation screenRotationAnimation =
    172                             displayAnimator.mScreenRotationAnimation;
    173                     if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
    174                         if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
    175                             setAnimating(true);
    176                         } else {
    177                             mBulkUpdateParams |= SET_UPDATE_ROTATION;
    178                             screenRotationAnimation.kill();
    179                             displayAnimator.mScreenRotationAnimation = null;
    180 
    181                             //TODO (multidisplay): Accessibility supported only for the default
    182                             // display.
    183                             if (accessibilityController != null && dc.isDefaultDisplay) {
    184                                 // We just finished rotation animation which means we did not
    185                                 // announce the rotation and waited for it to end, announce now.
    186                                 accessibilityController.onRotationChangedLocked(
    187                                         mService.getDefaultDisplayContentLocked());
    188                             }
    189                         }
    190                     }
    191 
    192                     // Update animations of all applications, including those
    193                     // associated with exiting/removed apps
    194                     ++mAnimTransactionSequence;
    195                     dc.updateWindowsForAnimator(this);
    196                     dc.updateWallpaperForAnimator(this);
    197                     dc.prepareSurfaces();
    198                 }
    199 
    200                 for (int i = 0; i < numDisplays; i++) {
    201                     final int displayId = mDisplayContentsAnimators.keyAt(i);
    202                     final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
    203 
    204                     dc.checkAppWindowsReadyToShow();
    205 
    206                     final ScreenRotationAnimation screenRotationAnimation =
    207                             mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
    208                     if (screenRotationAnimation != null) {
    209                         screenRotationAnimation.updateSurfaces(mTransaction);
    210                     }
    211                     orAnimating(dc.getDockedDividerController().animate(mCurrentTime));
    212                     //TODO (multidisplay): Magnification is supported only for the default display.
    213                     if (accessibilityController != null && dc.isDefaultDisplay) {
    214                         accessibilityController.drawMagnifiedRegionBorderIfNeededLocked();
    215                     }
    216                 }
    217 
    218                 if (!mAnimating) {
    219                     cancelAnimation();
    220                 }
    221 
    222                 if (mService.mWatermark != null) {
    223                     mService.mWatermark.drawIfNeeded();
    224                 }
    225 
    226                 SurfaceControl.mergeToGlobalTransaction(mTransaction);
    227             } catch (RuntimeException e) {
    228                 Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
    229             } finally {
    230                 mService.closeSurfaceTransaction("WindowAnimator");
    231                 if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
    232             }
    233 
    234             boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
    235             boolean doRequest = false;
    236             if (mBulkUpdateParams != 0) {
    237                 doRequest = mService.mRoot.copyAnimToLayoutParams();
    238             }
    239 
    240             if (hasPendingLayoutChanges || doRequest) {
    241                 mService.mWindowPlacerLocked.requestTraversal();
    242             }
    243 
    244             final boolean rootAnimating = mService.mRoot.isSelfOrChildAnimating();
    245             if (rootAnimating && !mLastRootAnimating) {
    246 
    247                 // Usually app transitions but quite a load onto the system already (with all the
    248                 // things happening in app), so pause task snapshot persisting to not increase the
    249                 // load.
    250                 mService.mTaskSnapshotController.setPersisterPaused(true);
    251                 Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
    252             }
    253             if (!rootAnimating && mLastRootAnimating) {
    254                 mService.mWindowPlacerLocked.requestTraversal();
    255                 mService.mTaskSnapshotController.setPersisterPaused(false);
    256                 Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
    257             }
    258 
    259             mLastRootAnimating = rootAnimating;
    260 
    261             if (mRemoveReplacedWindows) {
    262                 mService.mRoot.removeReplacedWindows();
    263                 mRemoveReplacedWindows = false;
    264             }
    265 
    266             mService.destroyPreservedSurfaceLocked();
    267 
    268             executeAfterPrepareSurfacesRunnables();
    269 
    270             if (DEBUG_WINDOW_TRACE) {
    271                 Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
    272                         + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
    273                         + " mPendingLayoutChanges(DEFAULT_DISPLAY)="
    274                         + Integer.toHexString(getPendingLayoutChanges(DEFAULT_DISPLAY)));
    275             }
    276         }
    277     }
    278 
    279     private static String bulkUpdateParamsToString(int bulkUpdateParams) {
    280         StringBuilder builder = new StringBuilder(128);
    281         if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) {
    282             builder.append(" UPDATE_ROTATION");
    283         }
    284         if ((bulkUpdateParams & WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE) != 0) {
    285             builder.append(" WALLPAPER_MAY_CHANGE");
    286         }
    287         if ((bulkUpdateParams & WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED) != 0) {
    288             builder.append(" FORCE_HIDING_CHANGED");
    289         }
    290         if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
    291             builder.append(" ORIENTATION_CHANGE_COMPLETE");
    292         }
    293         return builder.toString();
    294     }
    295 
    296     public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) {
    297         final String subPrefix = "  " + prefix;
    298         final String subSubPrefix = "  " + subPrefix;
    299 
    300         for (int i = 0; i < mDisplayContentsAnimators.size(); i++) {
    301             pw.print(prefix); pw.print("DisplayContentsAnimator #");
    302                     pw.print(mDisplayContentsAnimators.keyAt(i));
    303                     pw.println(":");
    304             final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
    305             final DisplayContent dc =
    306                     mService.mRoot.getDisplayContent(mDisplayContentsAnimators.keyAt(i));
    307             dc.dumpWindowAnimators(pw, subPrefix);
    308             if (displayAnimator.mScreenRotationAnimation != null) {
    309                 pw.print(subPrefix); pw.println("mScreenRotationAnimation:");
    310                 displayAnimator.mScreenRotationAnimation.printTo(subSubPrefix, pw);
    311             } else if (dumpAll) {
    312                 pw.print(subPrefix); pw.println("no ScreenRotationAnimation ");
    313             }
    314             pw.println();
    315         }
    316 
    317         pw.println();
    318 
    319         if (dumpAll) {
    320             pw.print(prefix); pw.print("mAnimTransactionSequence=");
    321                     pw.print(mAnimTransactionSequence);
    322             pw.print(prefix); pw.print("mCurrentTime=");
    323                     pw.println(TimeUtils.formatUptime(mCurrentTime));
    324         }
    325         if (mBulkUpdateParams != 0) {
    326             pw.print(prefix); pw.print("mBulkUpdateParams=0x");
    327                     pw.print(Integer.toHexString(mBulkUpdateParams));
    328                     pw.println(bulkUpdateParamsToString(mBulkUpdateParams));
    329         }
    330         if (mWindowDetachedWallpaper != null) {
    331             pw.print(prefix); pw.print("mWindowDetachedWallpaper=");
    332                 pw.println(mWindowDetachedWallpaper);
    333         }
    334     }
    335 
    336     int getPendingLayoutChanges(final int displayId) {
    337         if (displayId < 0) {
    338             return 0;
    339         }
    340         final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
    341         return (displayContent != null) ? displayContent.pendingLayoutChanges : 0;
    342     }
    343 
    344     void setPendingLayoutChanges(final int displayId, final int changes) {
    345         if (displayId < 0) {
    346             return;
    347         }
    348         final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
    349         if (displayContent != null) {
    350             displayContent.pendingLayoutChanges |= changes;
    351         }
    352     }
    353 
    354     private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
    355         if (displayId < 0) {
    356             return null;
    357         }
    358 
    359         DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
    360 
    361         // It is possible that this underlying {@link DisplayContent} has been removed. In this
    362         // case, we do not want to create an animator associated with it as {link #animate} will
    363         // fail.
    364         if (displayAnimator == null && mService.mRoot.getDisplayContent(displayId) != null) {
    365             displayAnimator = new DisplayContentsAnimator();
    366             mDisplayContentsAnimators.put(displayId, displayAnimator);
    367         }
    368         return displayAnimator;
    369     }
    370 
    371     void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) {
    372         final DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId);
    373 
    374         if (animator != null) {
    375             animator.mScreenRotationAnimation = animation;
    376         }
    377     }
    378 
    379     ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) {
    380         if (displayId < 0) {
    381             return null;
    382         }
    383 
    384         DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId);
    385         return animator != null? animator.mScreenRotationAnimation : null;
    386     }
    387 
    388     void requestRemovalOfReplacedWindows(WindowState win) {
    389         mRemoveReplacedWindows = true;
    390     }
    391 
    392     void scheduleAnimation() {
    393         if (!mAnimationFrameCallbackScheduled) {
    394             mAnimationFrameCallbackScheduled = true;
    395             mChoreographer.postFrameCallback(mAnimationFrameCallback);
    396         }
    397     }
    398 
    399     private void cancelAnimation() {
    400         if (mAnimationFrameCallbackScheduled) {
    401             mAnimationFrameCallbackScheduled = false;
    402             mChoreographer.removeFrameCallback(mAnimationFrameCallback);
    403         }
    404     }
    405 
    406     private class DisplayContentsAnimator {
    407         ScreenRotationAnimation mScreenRotationAnimation = null;
    408     }
    409 
    410     boolean isAnimating() {
    411         return mAnimating;
    412     }
    413 
    414     boolean isAnimationScheduled() {
    415         return mAnimationFrameCallbackScheduled;
    416     }
    417 
    418     Choreographer getChoreographer() {
    419         return mChoreographer;
    420     }
    421 
    422     void setAnimating(boolean animating) {
    423         mAnimating = animating;
    424     }
    425 
    426     void orAnimating(boolean animating) {
    427         mAnimating |= animating;
    428     }
    429 
    430     /**
    431      * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and
    432      * the corresponding transaction is closed and applied.
    433      */
    434     void addAfterPrepareSurfacesRunnable(Runnable r) {
    435         // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just
    436         // immediately execute the runnable passed in.
    437         if (mInExecuteAfterPrepareSurfacesRunnables) {
    438             r.run();
    439             return;
    440         }
    441 
    442         mAfterPrepareSurfacesRunnables.add(r);
    443         scheduleAnimation();
    444     }
    445 
    446     void executeAfterPrepareSurfacesRunnables() {
    447 
    448         // Don't even think about to start recursing!
    449         if (mInExecuteAfterPrepareSurfacesRunnables) {
    450             return;
    451         }
    452         mInExecuteAfterPrepareSurfacesRunnables = true;
    453 
    454         // Traverse in order they were added.
    455         final int size = mAfterPrepareSurfacesRunnables.size();
    456         for (int i = 0; i < size; i++) {
    457             mAfterPrepareSurfacesRunnables.get(i).run();
    458         }
    459         mAfterPrepareSurfacesRunnables.clear();
    460         mInExecuteAfterPrepareSurfacesRunnables = false;
    461     }
    462 }
    463