1 /* 2 * Copyright (C) 2023 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 android.server.wm.animations; 18 19 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertFalse; 23 import static org.junit.Assert.assertTrue; 24 25 import android.graphics.Color; 26 import android.os.Bundle; 27 import android.provider.Settings; 28 import android.server.wm.Condition; 29 import android.server.wm.WindowManagerState; 30 import android.server.wm.WindowManagerTestBase; 31 import android.server.wm.settings.SettingsSession; 32 import android.view.Display; 33 import android.view.Gravity; 34 import android.view.View; 35 import android.view.ViewGroup; 36 import android.view.Window; 37 import android.view.WindowManager; 38 39 import org.junit.ClassRule; 40 import org.junit.Test; 41 import org.junit.rules.TestRule; 42 43 /** 44 * Test the following APIs for controlling FLAG_NO_MOVE_ANIMATION: 45 * <ul> 46 * <li>{@code WindowManager.LayoutParams.setCanPlayMoveAnimation(boolean)} 47 * <li>{@code WindowManager.LayoutParams.canPlayMoveAnimation()} 48 * <li>{@code android:style/windowNoMoveAnimation} 49 * </ul> 50 * 51 * Build/Install/Run: 52 * atest CtsWindowManagerDeviceAnimations:MoveAnimationTests 53 */ 54 public class MoveAnimationTests extends WindowManagerTestBase { 55 56 /** 57 * All tests in this class run with window animation scaling set to 20.0f 58 */ 59 @ClassRule 60 public static final TestRule sWindowAnimationRule = SettingsSession.overrideForTest( 61 Settings.Global.getUriFor(Settings.Global.WINDOW_ANIMATION_SCALE), 62 Settings.Global::getFloat, 63 Settings.Global::putFloat, 64 20.0f); 65 66 /** 67 * Activity with a theme setting {@code windowIsFloating} as {@code true} to get the default 68 * behavior of floating window move animations. 69 */ 70 public static class FloatingActivity extends FocusableActivity { 71 72 protected View mContentView; 73 74 /** 75 * Instance of {@link FloatingActivity} with a theme setting {@code windowNoMoveAnimation} 76 * as {@code true}. 77 */ 78 public static class NoMove extends FloatingActivity { 79 @Override onCreate(Bundle savedInstanceState)80 protected void onCreate(Bundle savedInstanceState) { 81 super.onCreate(savedInstanceState); 82 } 83 } 84 85 @Override onCreate(Bundle savedInstanceState)86 protected void onCreate(Bundle savedInstanceState) { 87 super.onCreate(savedInstanceState); 88 89 mContentView = new View(this); 90 mContentView.setBackgroundColor(Color.BLUE); 91 92 setContentSquare(40); 93 } 94 setContentSquare(int size)95 public void setContentSquare(int size) { 96 getWindow() 97 .setLayout( 98 ViewGroup.LayoutParams.WRAP_CONTENT, 99 ViewGroup.LayoutParams.WRAP_CONTENT); 100 getWindow().setContentView(mContentView, new ViewGroup.LayoutParams(size, size)); 101 102 WindowManager.LayoutParams attrs = getWindow().getAttributes(); 103 attrs.gravity = Gravity.RIGHT | Gravity.BOTTOM; 104 getWindow().setAttributes(attrs); 105 } 106 } 107 108 @Test testCanPlayMoveAnimationByDefault()109 public void testCanPlayMoveAnimationByDefault() { 110 final FloatingActivity activity = 111 startActivityInWindowingModeFullScreen(FloatingActivity.class); 112 final Window window = activity.getWindow(); 113 114 // Default state should be TRUE because the activity has done nothing to override it. 115 assertTrue("Floating windows should play move animations by default", 116 window.getAttributes().canPlayMoveAnimation()); 117 assertPlaysMoveAnimation(activity, true); 118 } 119 120 @Test testCanOverrideTheme()121 public void testCanOverrideTheme() { 122 final FloatingActivity.NoMove activity = 123 startActivityInWindowingModeFullScreen(FloatingActivity.NoMove.class); 124 final Window window = activity.getWindow(); 125 126 // Default state should be FALSE because this Activity uses a theme with no move animation. 127 assertFalse("Themes should be able to prevent move animations via windowNoMoveAnimation", 128 window.getAttributes().canPlayMoveAnimation()); 129 130 // Window API should be able to override theme defaults from FALSE to TRUE. 131 getInstrumentation().runOnMainSync(() -> { 132 WindowManager.LayoutParams attrs = window.getAttributes(); 133 attrs.setCanPlayMoveAnimation(true); 134 window.setAttributes(attrs); 135 }); 136 137 assertTrue("Window should know that it can play a move animation", 138 window.getAttributes().canPlayMoveAnimation()); 139 assertPlaysMoveAnimation(activity, true); 140 } 141 142 @Test testThemeCanDisable()143 public void testThemeCanDisable() { 144 final FloatingActivity.NoMove activity = 145 startActivityInWindowingModeFullScreen(FloatingActivity.NoMove.class); 146 final Window window = activity.getWindow(); 147 148 // Window API should be able to override theme defaults from TRUE to FALSE. 149 getInstrumentation().runOnMainSync(() -> { 150 WindowManager.LayoutParams attrs = window.getAttributes(); 151 attrs.setCanPlayMoveAnimation(false); 152 window.setAttributes(attrs); 153 }); 154 155 assertFalse("Window should know that it can NOT play a move animation", 156 window.getAttributes().canPlayMoveAnimation()); 157 assertPlaysMoveAnimation(activity, false); 158 } 159 assertPlaysMoveAnimation(final FloatingActivity activity, final boolean isPlayed)160 private void assertPlaysMoveAnimation(final FloatingActivity activity, final boolean isPlayed) { 161 mWmState.waitForAppTransitionIdleOnDisplay(Display.DEFAULT_DISPLAY); 162 163 activity.mContentView.post(() -> activity.setContentSquare(200)); 164 165 Condition isAnimating = new Condition("Window is animating", 166 () -> { 167 mWmState.computeState(); 168 WindowManagerState.Activity ar = 169 mWmState.getActivity(activity.getComponentName()); 170 return ar != null && ar.isAnimating(); 171 }) 172 .setRetryIntervalMs(16) 173 .setRetryLimit(50); 174 assertEquals(isPlayed, Condition.waitFor(isAnimating)); 175 } 176 } 177