Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7bcdb33d authored by Winson Chung's avatar Winson Chung Committed by Android (Google) Code Review
Browse files

Merge "Adding support for clipping window transition for alternate recents."

parents 9eaf8864 399f6205
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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 android.view.animation;

import android.graphics.Rect;

/**
 * An animation that controls the clip of an object. See the
 * {@link android.view.animation full package} description for details and
 * sample code.
 *
 * @hide
 */
public class ClipRectAnimation extends Animation {
    private Rect mFromRect = new Rect();
    private Rect mToRect = new Rect();

    /**
     * Constructor to use when building a ClipRectAnimation from code
     *
     * @param fromClip the clip rect to animate from
     * @param toClip the clip rect to animate to
     */
    public ClipRectAnimation(Rect fromClip, Rect toClip) {
        if (fromClip == null || toClip == null) {
            throw new RuntimeException("Expected non-null animation clip rects");
        }
        mFromRect.set(fromClip);
        mToRect.set(toClip);
    }

    @Override
    protected void applyTransformation(float it, Transformation tr) {
        int l = mFromRect.left + (int) ((mToRect.left - mFromRect.left) * it);
        int t = mFromRect.top + (int) ((mToRect.top - mFromRect.top) * it);
        int r = mFromRect.right + (int) ((mToRect.right - mFromRect.right) * it);
        int b = mFromRect.bottom + (int) ((mToRect.bottom - mFromRect.bottom) * it);
        tr.setClipRect(l, t, r, b);
    }

    @Override
    public boolean willChangeTransformationMatrix() {
        return false;
    }
}
+52 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.view.animation;

import android.graphics.Matrix;
import android.graphics.Rect;

import java.io.PrintWriter;

@@ -47,6 +48,9 @@ public class Transformation {
    protected float mAlpha;
    protected int mTransformationType;

    private boolean mHasClipRect;
    private Rect mClipRect = new Rect();

    /**
     * Creates a new transformation with alpha = 1 and the identity matrix.
     */
@@ -65,6 +69,8 @@ public class Transformation {
        } else {
            mMatrix.reset();
        }
        mClipRect.setEmpty();
        mHasClipRect = false;
        mAlpha = 1.0f;
        mTransformationType = TYPE_BOTH;
    }
@@ -98,6 +104,12 @@ public class Transformation {
    public void set(Transformation t) {
        mAlpha = t.getAlpha();
        mMatrix.set(t.getMatrix());
        if (t.mHasClipRect) {
            setClipRect(t.getClipRect());
        } else {
            mHasClipRect = false;
            mClipRect.setEmpty();
        }
        mTransformationType = t.getTransformationType();
    }

@@ -109,6 +121,9 @@ public class Transformation {
    public void compose(Transformation t) {
        mAlpha *= t.getAlpha();
        mMatrix.preConcat(t.getMatrix());
        if (t.mHasClipRect) {
            setClipRect(t.getClipRect());
        }
    }
    
    /**
@@ -119,6 +134,9 @@ public class Transformation {
    public void postCompose(Transformation t) {
        mAlpha *= t.getAlpha();
        mMatrix.postConcat(t.getMatrix());
        if (t.mHasClipRect) {
            setClipRect(t.getClipRect());
        }
    }

    /**
@@ -137,6 +155,39 @@ public class Transformation {
        mAlpha = alpha;
    }

    /**
     * Sets the current Transform's clip rect
     * @hide
     */
    public void setClipRect(Rect r) {
        setClipRect(r.left, r.top, r.right, r.bottom);
    }

    /**
     * Sets the current Transform's clip rect
     * @hide
     */
    public void setClipRect(int l, int t, int r, int b) {
        mClipRect.set(l, t, r, b);
        mHasClipRect = true;
    }

    /**
     * Returns the current Transform's clip rect
     * @hide
     */
    public Rect getClipRect() {
        return mClipRect;
    }

    /**
     * Returns whether the current Transform's clip rect is set
     * @hide
     */
    public boolean hasClipRect() {
        return mHasClipRect;
    }

    /**
     * @return The degree of transparency
     */
+218 −54
Original line number Diff line number Diff line
@@ -19,18 +19,22 @@ package com.android.server.wm;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Debug;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.SystemProperties;
import android.util.Slog;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.ClipRectAnimation;
import android.view.animation.Interpolator;
import android.view.animation.ScaleAnimation;

import android.view.animation.TranslateAnimation;
import com.android.internal.util.DumpUtils.Dump;
import com.android.server.AttributeCache;
import com.android.server.wm.WindowManagerService.H;
@@ -125,6 +129,12 @@ public class AppTransition implements Dump {
    private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
    private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;

    // These are the possible states for the enter/exit activities during a thumbnail transition
    private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
    private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1;
    private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2;
    private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;

    private String mNextAppTransitionPackage;
    private Bitmap mNextAppTransitionThumbnail;
    // Used for thumbnail transitions. True if we're scaling up, false if scaling down
@@ -148,10 +158,13 @@ public class AppTransition implements Dump {
    private final Interpolator mThumbnailFadeoutInterpolator;

    private int mCurrentUserId = 0;
    private boolean mUseAlternateThumbnailAnimation;

    AppTransition(Context context, Handler h) {
        mContext = context;
        mH = h;
        mUseAlternateThumbnailAnimation =
                SystemProperties.getBoolean("persist.anim.use_alt_thumbnail", false);
        mConfigShortAnimTime = context.getResources().getInteger(
                com.android.internal.R.integer.config_shortAnimTime);
        mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
@@ -384,17 +397,62 @@ public class AppTransition implements Dump {
        return a;
    }

    Animation createThumbnailAnimationLocked(int transit, boolean enter, boolean thumb,
                                    int appWidth, int appHeight) {
    /**
     * Prepares the specified animation with a standard duration, interpolator, etc.
     */
    Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
        // Pick the desired duration.  If this is an inter-activity transition,
        // it  is the standard duration for that.  Otherwise we use the longer
        // task transition duration.
        final long duration;
        switch (transit) {
            case TRANSIT_ACTIVITY_OPEN:
            case TRANSIT_ACTIVITY_CLOSE:
                duration = mConfigShortAnimTime;
                break;
            default:
                duration = DEFAULT_APP_TRANSITION_DURATION;
                break;
        }
        a.setDuration(duration);
        a.setFillAfter(true);
        a.setInterpolator(mDecelerateInterpolator);
        a.initialize(appWidth, appHeight, appWidth, appHeight);
        return a;
    }

    /**
     * Return the current thumbnail transition state.
     */
    int getThumbnailTransitionState(boolean enter) {
        if (enter) {
            if (mNextAppTransitionScaleUp) {
                return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
            } else {
                return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
            }
        } else {
            if (mNextAppTransitionScaleUp) {
                return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
            } else {
                return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
            }
        }
    }

    /**
     * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
     * when a thumbnail is specified with the activity options.
     */
    Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit) {
        Animation a;
        final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
        final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
        if (thumb) {
            // Animation for zooming thumbnail from its initial size to
            // filling the screen.

        if (mNextAppTransitionScaleUp) {
            // Animation for the thumbnail zooming from its initial size to the full screen
            float scaleW = appWidth / thumbWidth;
            float scaleH = appHeight / thumbHeight;
            Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
@@ -411,27 +469,131 @@ public class AppTransition implements Dump {
            set.addAnimation(alpha);
            a = set;
        } else {
            // Animation for the thumbnail zooming down from the full screen to its final size
            float scaleW = appWidth / thumbWidth;
            float scaleH = appHeight / thumbHeight;
            a = new ScaleAnimation(scaleW, 1, scaleH, 1,
                    computePivot(mNextAppTransitionStartX, 1 / scaleW),
                    computePivot(mNextAppTransitionStartY, 1 / scaleH));
        }
        } else if (enter) {
            // Entering app zooms out from the center of the thumbnail.
            if (mNextAppTransitionScaleUp) {

        return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
    }

    /**
     * This alternate animation is created when we are doing a thumbnail transition, for the
     * activity that is leaving, and the activity that is entering.
     */
    Animation createAlternateThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth,
                                                    int appHeight, int transit,
                                                    Rect containingFrame, Rect contentInsets) {
        Animation a;
        final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
        final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;

        switch (thumbTransitState) {
            case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
                // Entering app scales up with the thumbnail
                float scale = thumbWidth / appWidth;
                int unscaledThumbHeight = (int) (thumbHeight / scale);
                int scaledTopDecor = (int) (scale * contentInsets.top);
                Rect fromClipRect = new Rect(containingFrame);
                fromClipRect.bottom = (fromClipRect.top + unscaledThumbHeight);
                Rect toClipRect = new Rect(containingFrame);

                Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
                        computePivot(mNextAppTransitionStartX, scale),
                        computePivot(mNextAppTransitionStartY, scale));
                Animation alphaAnim = new AlphaAnimation(1, 1);
                Animation clipAnim = new ClipRectAnimation(fromClipRect, toClipRect);
                Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);

                AnimationSet set = new AnimationSet(true);
                set.addAnimation(alphaAnim);
                set.addAnimation(clipAnim);
                set.addAnimation(scaleAnim);
                set.addAnimation(translateAnim);
                a = set;
                break;
            }
            case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
                // Exiting app while the thumbnail is scaling up should fade
                if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
                    // Fade out while bringing up selected activity. This keeps the
                    // current activity from showing through a launching wallpaper
                    // activity.
                    a = new AlphaAnimation(1, 0);
                } else {
                    // noop animation
                    a = new AlphaAnimation(1, 1);
                }
                break;
            }
            case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
                // Entering the other app, it should just be visible while we scale the thumbnail
                // down above it
                a = new AlphaAnimation(1, 1);
                break;
            }
            case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
                // Exiting the current app, the app should scale down with the thumbnail
                float scale = thumbWidth / appWidth;
                int unscaledThumbHeight = (int) (thumbHeight / scale);
                int scaledTopDecor = (int) (scale * contentInsets.top);
                Rect fromClipRect = new Rect(containingFrame);
                Rect toClipRect = new Rect(containingFrame);
                toClipRect.bottom = (toClipRect.top + unscaledThumbHeight);

                Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
                        computePivot(mNextAppTransitionStartX, scale),
                        computePivot(mNextAppTransitionStartY, scale));
                Animation alphaAnim = new AlphaAnimation(1, 1);
                Animation clipAnim = new ClipRectAnimation(fromClipRect, toClipRect);
                Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);

                AnimationSet set = new AnimationSet(true);
                set.addAnimation(alphaAnim);
                set.addAnimation(clipAnim);
                set.addAnimation(scaleAnim);
                set.addAnimation(translateAnim);

                a = set;
                a.setZAdjustment(Animation.ZORDER_TOP);
                break;
            }
            default:
                throw new RuntimeException("Invalid thumbnail transition state");
        }

        return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
    }

    /**
     * This animation is created when we are doing a thumbnail transition, for the activity that is
     * leaving, and the activity that is entering.
     */
    Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth,
                                                    int appHeight, int transit) {
        Animation a;
        final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
        final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;

        switch (thumbTransitState) {
            case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
                // Entering app scales up with the thumbnail
                float scaleW = thumbWidth / appWidth;
                float scaleH = thumbHeight / appHeight;
                a = new ScaleAnimation(scaleW, 1, scaleH, 1,
                        computePivot(mNextAppTransitionStartX, scaleW),
                        computePivot(mNextAppTransitionStartY, scaleH));
            } else {
                // noop animation
                a = new AlphaAnimation(1, 1);
                break;
            }
        } else {
            // Exiting app
            if (mNextAppTransitionScaleUp) {
            case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
                // Exiting app while the thumbnail is scaling up should fade or stay in place
                if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
                    // Fade out while bringing up selected activity. This keeps the
                    // current activity from showing through a launching wallpaper
@@ -441,7 +603,16 @@ public class AppTransition implements Dump {
                    // noop animation
                    a = new AlphaAnimation(1, 1);
                }
            } else {
                break;
            }
            case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
                // Entering the other app, it should just be visible while we scale the thumbnail
                // down above it
                a = new AlphaAnimation(1, 1);
                break;
            }
            case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
                // Exiting the current app, the app should scale down with the thumbnail
                float scaleW = thumbWidth / appWidth;
                float scaleH = thumbHeight / appHeight;
                Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
@@ -455,32 +626,18 @@ public class AppTransition implements Dump {
                set.addAnimation(alpha);
                set.setZAdjustment(Animation.ZORDER_TOP);
                a = set;
            }
        }

        // Pick the desired duration.  If this is an inter-activity transition,
        // it  is the standard duration for that.  Otherwise we use the longer
        // task transition duration.
        final long duration;
        switch (transit) {
            case TRANSIT_ACTIVITY_OPEN:
            case TRANSIT_ACTIVITY_CLOSE:
                duration = mConfigShortAnimTime;
                break;
            }
            default:
                duration = DEFAULT_APP_TRANSITION_DURATION;
                break;
                throw new RuntimeException("Invalid thumbnail transition state");
        }
        a.setDuration(duration);
        a.setFillAfter(true);
        a.setInterpolator(mDecelerateInterpolator);
        a.initialize(appWidth, appHeight, appWidth, appHeight);
        return a;

        return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
    }


    Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
                            int appWidth, int appHeight) {
                            int appWidth, int appHeight, Rect containingFrame, Rect contentInsets) {
        Animation a;
        if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
            a = loadAnimation(mNextAppTransitionPackage, enter ?
@@ -501,7 +658,14 @@ public class AppTransition implements Dump {
                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
            mNextAppTransitionScaleUp =
                    (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
            a = createThumbnailAnimationLocked(transit, enter, false, appWidth, appHeight);
            if (mUseAlternateThumbnailAnimation) {
                a = createAlternateThumbnailEnterExitAnimationLocked(
                        getThumbnailTransitionState(enter), appWidth, appHeight, transit,
                        containingFrame, contentInsets);
            } else {
                a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
                        appWidth, appHeight, transit);
            }
            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                String animName = mNextAppTransitionScaleUp ?
                        "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
+22 −5
Original line number Diff line number Diff line
@@ -3155,7 +3155,22 @@ public class WindowManagerService extends IWindowManager.Stub
            final int height = displayInfo.appHeight;
            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, "applyAnimation: atoken="
                    + atoken);
            Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height);

            // Determine the visible rect to calculate the thumbnail clip
            WindowState win = atoken.findMainWindow();
            Rect containingFrame = new Rect(0, 0, width, height);
            Rect contentInsets = new Rect();
            if (win != null) {
                if (win.mContainingFrame != null) {
                    containingFrame.set(win.mContainingFrame);
                }
                if (win.mContentInsets != null) {
                    contentInsets.set(win.mContentInsets);
                }
            }

            Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
                    containingFrame, contentInsets);
            if (a != null) {
                if (DEBUG_ANIM) {
                    RuntimeException e = null;
@@ -8608,11 +8623,13 @@ public class WindowManagerService extends IWindowManager.Stub
                wtoken.deferClearAllDrawn = false;
            }

            boolean useAlternateThumbnailAnimation =
                            SystemProperties.getBoolean("persist.anim.use_alt_thumbnail", false);
            AppWindowAnimator appAnimator =
                    topOpeningApp == null ? null : topOpeningApp.mAppAnimator;
            Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();
            if (nextAppTransitionThumbnail != null && appAnimator != null
                    && appAnimator.animation != null) {
            if (!useAlternateThumbnailAnimation && nextAppTransitionThumbnail != null
                    && appAnimator != null && appAnimator.animation != null) {
                // This thumbnail animation is very special, we need to have
                // an extra surface with the thumbnail included with the animation.
                Rect dirty = new Rect(0, 0, nextAppTransitionThumbnail.getWidth(),
@@ -8636,8 +8653,8 @@ public class WindowManagerService extends IWindowManager.Stub
                    drawSurface.release();
                    appAnimator.thumbnailLayer = topOpeningLayer;
                    DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
                    Animation anim = mAppTransition.createThumbnailAnimationLocked(
                            transit, true, true, displayInfo.appWidth, displayInfo.appHeight);
                    Animation anim = mAppTransition.createThumbnailScaleAnimationLocked(
                            displayInfo.appWidth, displayInfo.appHeight, transit);
                    appAnimator.thumbnailAnimation = anim;
                    anim.restrictDuration(MAX_ANIMATION_DURATION);
                    anim.scaleCurrentDuration(mTransitionAnimationScale);
+32 −7
Original line number Diff line number Diff line
@@ -113,6 +113,11 @@ class WindowStateAnimator {
    float mAlpha = 0;
    float mLastAlpha = 0;

    boolean mHasClipRect;
    Rect mClipRect = new Rect();
    Rect mTmpClipRect = new Rect();
    Rect mLastClipRect = new Rect();

    // Used to save animation distances between the time they are calculated and when they are
    // used.
    int mAnimDw;
@@ -951,6 +956,7 @@ class WindowStateAnimator {
            if (screenAnimation) {
                tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
            }

            //TODO (multidisplay): Magnification is supported only for the default display.
            if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) {
                MagnificationSpec spec = mService.mAccessibilityController
@@ -985,6 +991,7 @@ class WindowStateAnimator {
            // transforming since it is more important to have that
            // animation be smooth.
            mShownAlpha = mAlpha;
            mHasClipRect = false;
            if (!mService.mLimitedAlphaCompositing
                    || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
                    || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
@@ -998,6 +1005,10 @@ class WindowStateAnimator {
                }
                if (appTransformation != null) {
                    mShownAlpha *= appTransformation.getAlpha();
                    if (appTransformation.hasClipRect()) {
                        mClipRect.set(appTransformation.getClipRect());
                        mHasClipRect = true;
                    }
                }
                if (mAnimator.mUniverseBackground != null) {
                    mShownAlpha *= mAnimator.mUniverseBackground.mUniverseTransform.getAlpha();
@@ -1149,15 +1160,29 @@ class WindowStateAnimator {
            applyDecorRect(w.mDecorFrame);
        }

        if (!w.mSystemDecorRect.equals(w.mLastSystemDecorRect)) {
            w.mLastSystemDecorRect.set(w.mSystemDecorRect);
        // By default, the clip rect is the system decor rect
        Rect clipRect = w.mSystemDecorRect;
        if (mHasClipRect) {

            // If we have an animated clip rect, intersect it with the system decor rect
            int offsetTop = w.mSystemDecorRect.top;
            mTmpClipRect.set(w.mSystemDecorRect);
            mTmpClipRect.offset(0, -offsetTop);
            mTmpClipRect.intersect(mClipRect);
            mTmpClipRect.offset(0, offsetTop);
            clipRect = mTmpClipRect;

        }

        if (!clipRect.equals(mLastClipRect)) {
            mLastClipRect.set(clipRect);
            try {
                if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
                        "CROP " + w.mSystemDecorRect.toShortString(), null);
                mSurfaceControl.setWindowCrop(w.mSystemDecorRect);
                        "CROP " + clipRect.toShortString(), null);
                mSurfaceControl.setWindowCrop(clipRect);
            } catch (RuntimeException e) {
                Slog.w(TAG, "Error setting crop surface of " + w
                        + " crop=" + w.mSystemDecorRect.toShortString(), e);
                        + " crop=" + clipRect.toShortString(), e);
                if (!recoveringMemory) {
                    mService.reclaimSomeSurfaceMemoryLocked(this, "crop", true);
                }