1 /* 2 * Copyright (C) 2019 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.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 23 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; 24 25 import static org.junit.Assert.assertEquals; 26 import static org.junit.Assert.assertFalse; 27 import static org.junit.Assert.assertNotNull; 28 import static org.junit.Assert.assertNull; 29 import static org.junit.Assert.assertTrue; 30 31 import android.os.IBinder; 32 import android.platform.test.annotations.Presubmit; 33 import android.view.Display; 34 import android.view.IRemoteAnimationFinishedCallback; 35 import android.view.IRemoteAnimationRunner; 36 import android.view.RemoteAnimationAdapter; 37 import android.view.RemoteAnimationDefinition; 38 import android.view.RemoteAnimationTarget; 39 import android.view.WindowManager; 40 41 import androidx.test.filters.SmallTest; 42 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 46 /** 47 * Tests for change transitions 48 * 49 * Build/Install/Run: 50 * atest WmTests:AppChangeTransitionTests 51 */ 52 @SmallTest 53 @Presubmit 54 @RunWith(WindowTestRunner.class) 55 public class AppChangeTransitionTests extends WindowTestsBase { 56 57 private Task mTask; 58 private ActivityRecord mActivity; 59 setUpOnDisplay(DisplayContent dc)60 public void setUpOnDisplay(DisplayContent dc) { 61 mActivity = createActivityRecord(dc, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD); 62 mTask = mActivity.getTask(); 63 64 // Set a remote animator with snapshot disabled. Snapshots don't work in wmtests. 65 RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); 66 RemoteAnimationAdapter adapter = 67 new RemoteAnimationAdapter(new TestRemoteAnimationRunner(), 10, 1, false); 68 definition.addRemoteAnimation(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE, adapter); 69 dc.registerRemoteAnimations(definition); 70 } 71 72 class TestRemoteAnimationRunner implements IRemoteAnimationRunner { 73 @Override onAnimationStart(@indowManager.TransitionOldType int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback)74 public void onAnimationStart(@WindowManager.TransitionOldType int transit, 75 RemoteAnimationTarget[] apps, 76 RemoteAnimationTarget[] wallpapers, 77 RemoteAnimationTarget[] nonApps, 78 IRemoteAnimationFinishedCallback finishedCallback) { 79 for (RemoteAnimationTarget target : apps) { 80 assertNotNull(target.startBounds); 81 } 82 try { 83 finishedCallback.onAnimationFinished(); 84 } catch (Exception e) { 85 throw new RuntimeException("Something went wrong"); 86 } 87 } 88 89 @Override onAnimationCancelled()90 public void onAnimationCancelled() { 91 } 92 93 @Override asBinder()94 public IBinder asBinder() { 95 return null; 96 } 97 } 98 99 @Test testModeChangeRemoteAnimatorNoSnapshot()100 public void testModeChangeRemoteAnimatorNoSnapshot() { 101 // setup currently defaults to no snapshot. 102 setUpOnDisplay(mDisplayContent); 103 104 mTask.setWindowingMode(WINDOWING_MODE_FREEFORM); 105 assertEquals(1, mDisplayContent.mChangingContainers.size()); 106 107 // Verify we are in a change transition, but without a snapshot. 108 // Though, the test will actually have crashed by now if a snapshot is attempted. 109 assertNull(mTask.mSurfaceFreezer.mSnapshot); 110 assertTrue(mTask.isInChangeTransition()); 111 112 waitUntilHandlersIdle(); 113 mActivity.removeImmediately(); 114 } 115 116 @Test testCancelPendingChangeOnRemove()117 public void testCancelPendingChangeOnRemove() { 118 // setup currently defaults to no snapshot. 119 setUpOnDisplay(mDisplayContent); 120 121 mTask.setWindowingMode(WINDOWING_MODE_FREEFORM); 122 assertEquals(1, mDisplayContent.mChangingContainers.size()); 123 assertTrue(mTask.isInChangeTransition()); 124 125 // Removing the app-token from the display should clean-up the 126 // the change leash. 127 mDisplayContent.removeAppToken(mActivity.token); 128 assertEquals(0, mDisplayContent.mChangingContainers.size()); 129 assertFalse(mTask.isInChangeTransition()); 130 131 waitUntilHandlersIdle(); 132 mActivity.removeImmediately(); 133 } 134 135 @Test testNoChangeOnOldDisplayWhenMoveDisplay()136 public void testNoChangeOnOldDisplayWhenMoveDisplay() { 137 mDisplayContent.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN); 138 final DisplayContent dc1 = createNewDisplay(Display.STATE_ON); 139 dc1.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FREEFORM); 140 setUpOnDisplay(dc1); 141 142 assertEquals(WINDOWING_MODE_FREEFORM, mTask.getWindowingMode()); 143 144 // Reparenting to a display with different windowing mode may trigger 145 // a change transition internally, but it should be cleaned-up once 146 // the display change is complete. 147 mTask.reparent(mDisplayContent.getDefaultTaskDisplayArea(), true); 148 149 assertEquals(WINDOWING_MODE_FULLSCREEN, mTask.getWindowingMode()); 150 151 // Make sure the change transition is not the old display 152 assertFalse(dc1.mChangingContainers.contains(mTask)); 153 154 waitUntilHandlersIdle(); 155 mActivity.removeImmediately(); 156 } 157 158 @Test testCancelPendingChangeOnHide()159 public void testCancelPendingChangeOnHide() { 160 // setup currently defaults to no snapshot. 161 setUpOnDisplay(mDisplayContent); 162 163 mTask.setWindowingMode(WINDOWING_MODE_FREEFORM); 164 assertEquals(1, mDisplayContent.mChangingContainers.size()); 165 assertTrue(mTask.isInChangeTransition()); 166 167 // Changing visibility should cancel the change transition and become closing 168 mActivity.setVisibility(false); 169 assertEquals(0, mDisplayContent.mChangingContainers.size()); 170 assertFalse(mTask.isInChangeTransition()); 171 172 waitUntilHandlersIdle(); 173 mActivity.removeImmediately(); 174 } 175 } 176