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