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

Commit 399f6205 authored by Winson Chung's avatar Winson Chung
Browse files

Adding support for clipping window transition for alternate recents.

Change-Id: Ic7df4e6c0396afc794ffc21694814c0a93f20f31
parent ea818400
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
@@ -3235,7 +3235,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;
@@ -8716,11 +8731,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(),
@@ -8744,8 +8761,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.mDisplayMagnifier != null && displayId == Display.DEFAULT_DISPLAY) {
                MagnificationSpec spec = mService.mDisplayMagnifier
@@ -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);
                }