In general, app main window the animation should applied by
AppWindowToken#applyAnimationLocked through app transition.
We should avoid application can apply animation through
WM.LayoutParams.windowAnimation for app main window.
We also ignore application to customize starting window animation,
since starting window is a special window for displaying while app
starting, application should not use or change animation directly.
Bug:
133274628
Test: atest AppTransitionTests
Test: manual, as below steps:
1) Launch apps (i.e. Pocketcasts) that override windowAnimation style
with custom animation for app main window or starting window
(TYPE_BASE_APPLICATION | TYPE_APPLICATION_STARTING).
2) In gesture nav, swipe left & right back on nav bar.
3) Expect the app's main window should not have animation or flick.
Change-Id: Ibeac1e513023ab19bcfb7ee412f41a570e917a17
import android.content.res.ResourceId;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
private final boolean mGridLayoutRecentsEnabled;
private final boolean mLowRamRecentsEnabled;
+ private final int mDefaultWindowAnimationStyleResId;
+
private RemoteAnimationController mRemoteAnimationController;
final Handler mHandler;
* mContext.getResources().getDisplayMetrics().density);
mGridLayoutRecentsEnabled = SystemProperties.getBoolean("ro.recents.grid", false);
mLowRamRecentsEnabled = ActivityManager.isLowRamDeviceStatic();
+
+ final TypedArray windowStyle = mContext.getTheme().obtainStyledAttributes(
+ com.android.internal.R.styleable.Window);
+ mDefaultWindowAnimationStyleResId = windowStyle.getResourceId(
+ com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
+ windowStyle.recycle();
}
boolean isTransitionSet() {
return redoLayout;
}
+ @VisibleForTesting
+ int getDefaultWindowAnimationStyleResId() {
+ return mDefaultWindowAnimationStyleResId;
+ }
+
+ /** Returns window animation style ID from {@link LayoutParams} or from system in some cases */
+ @VisibleForTesting
+ int getAnimationStyleResId(@NonNull LayoutParams lp) {
+ int resId = lp.windowAnimations;
+ if (lp.type == LayoutParams.TYPE_APPLICATION_STARTING) {
+ // Note that we don't want application to customize starting window animation.
+ // Since this window is specific for displaying while app starting,
+ // application should not change its animation directly.
+ // In this case, it will use system resource to get default animation.
+ resId = mDefaultWindowAnimationStyleResId;
+ }
+ return resId;
+ }
+
private AttributeCache.Entry getCachedAnimations(LayoutParams lp) {
if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
+ (lp != null ? lp.packageName : null)
// application resources. It is nice to avoid loading application
// resources if we can.
String packageName = lp.packageName != null ? lp.packageName : "android";
- int resId = lp.windowAnimations;
+ int resId = getAnimationStyleResId(lp);
if ((resId&0xFF000000) == 0x01000000) {
packageName = "android";
}
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_NONE;
if (mWin.mSkipEnterAnimationForSeamlessReplacement) {
return;
}
+
+ // We don't apply animation for application main window here since this window type
+ // should be controlled by AppWindowToken in general.
+ if (mAttrType == TYPE_BASE_APPLICATION) {
+ return;
+ }
+
final int transit;
if (mEnterAnimationPending) {
mEnterAnimationPending = false;
+ " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
+ " a=" + a
+ " transit=" + transit
+ + " type=" + mAttrType
+ " isEntrance=" + isEntrance + " Callers " + Debug.getCallers(3));
if (a != null) {
if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
+import android.view.WindowManager;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
assertTrue(runner.mCancelled);
}
+ @Test
+ public void testGetAnimationStyleResId() {
+ // Verify getAnimationStyleResId will return as LayoutParams.windowAnimations when without
+ // specifying window type.
+ final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams();
+ attrs.windowAnimations = 0x12345678;
+ assertEquals(attrs.windowAnimations, mDc.mAppTransition.getAnimationStyleResId(attrs));
+
+ // Verify getAnimationStyleResId will return system resource Id when the window type is
+ // starting window.
+ attrs.type = TYPE_APPLICATION_STARTING;
+ assertEquals(mDc.mAppTransition.getDefaultWindowAnimationStyleResId(),
+ mDc.mAppTransition.getAnimationStyleResId(attrs));
+ }
+
private class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
boolean mCancelled = false;
@Override