1 /* 2 * Copyright (C) 2021 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.systemui.shared.system; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 21 import static android.view.RemoteAnimationTarget.MODE_CHANGING; 22 import static android.view.RemoteAnimationTarget.MODE_CLOSING; 23 import static android.view.RemoteAnimationTarget.MODE_OPENING; 24 import static android.view.WindowManager.TRANSIT_CHANGE; 25 import static android.view.WindowManager.TRANSIT_CLOSE; 26 import static android.view.WindowManager.TRANSIT_OPEN; 27 import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; 28 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; 29 import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER; 30 import static android.window.TransitionInfo.FLAG_TRANSLUCENT; 31 32 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 33 import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR; 34 35 import static org.junit.Assert.assertEquals; 36 import static org.junit.Assert.assertTrue; 37 import static org.junit.Assert.fail; 38 import static org.mockito.Mockito.mock; 39 40 import android.app.ActivityManager; 41 import android.graphics.Rect; 42 import android.testing.AndroidTestingRunner; 43 import android.testing.TestableLooper; 44 import android.view.RemoteAnimationTarget; 45 import android.view.SurfaceControl; 46 import android.view.WindowManager; 47 import android.window.TransitionInfo; 48 49 import androidx.test.filters.SmallTest; 50 51 import com.android.systemui.SysuiTestCase; 52 import com.android.systemui.animation.RemoteAnimationTargetCompat; 53 import com.android.wm.shell.shared.TransitionUtil; 54 55 import org.junit.Before; 56 import org.junit.Test; 57 import org.junit.runner.RunWith; 58 import org.mockito.MockitoAnnotations; 59 60 @SmallTest 61 @RunWith(AndroidTestingRunner.class) 62 @TestableLooper.RunWithLooper 63 public class RemoteTransitionTest extends SysuiTestCase { 64 65 @Before setUp()66 public void setUp() { 67 MockitoAnnotations.initMocks(this); 68 } 69 70 @Test testLegacyTargetExtract()71 public void testLegacyTargetExtract() { 72 TransitionInfo combined = new TransitionInfoBuilder(TRANSIT_CLOSE) 73 .addChange(TRANSIT_CHANGE, FLAG_SHOW_WALLPAPER, 74 createTaskInfo(1 /* taskId */, ACTIVITY_TYPE_STANDARD)) 75 // Embedded TaskFragment should be excluded when animated with Task. 76 .addChange(TRANSIT_CLOSE, FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY, null /* taskInfo */) 77 .addChange(TRANSIT_CLOSE, 0 /* flags */, 78 createTaskInfo(2 /* taskId */, ACTIVITY_TYPE_STANDARD)) 79 .addChange(TRANSIT_OPEN, FLAG_IS_WALLPAPER, null /* taskInfo */) 80 .addChange(TRANSIT_CHANGE, FLAG_IS_DIVIDER_BAR, null /* taskInfo */) 81 .build(); 82 // Check apps extraction 83 RemoteAnimationTarget[] wrapped = RemoteAnimationTargetCompat.wrapApps(combined, 84 mock(SurfaceControl.Transaction.class), null /* leashes */); 85 assertEquals(2, wrapped.length); 86 int changeLayer = -1; 87 int closeLayer = -1; 88 for (RemoteAnimationTarget t : wrapped) { 89 if (t.mode == MODE_CHANGING) { 90 changeLayer = t.prefixOrderIndex; 91 } else if (t.mode == MODE_CLOSING) { 92 closeLayer = t.prefixOrderIndex; 93 } else { 94 fail(); 95 } 96 } 97 // verify ordering 98 assertTrue(closeLayer < changeLayer); 99 100 // Check wallpaper extraction 101 RemoteAnimationTarget[] wallps = RemoteAnimationTargetCompat.wrapNonApps(combined, 102 true /* wallpapers */, mock(SurfaceControl.Transaction.class), null /* leashes */); 103 assertEquals(1, wallps.length); 104 assertTrue(wallps[0].prefixOrderIndex < closeLayer); 105 assertEquals(MODE_OPENING, wallps[0].mode); 106 107 // Check non-apps extraction 108 RemoteAnimationTarget[] nonApps = RemoteAnimationTargetCompat.wrapNonApps(combined, 109 false /* wallpapers */, mock(SurfaceControl.Transaction.class), null /* leashes */); 110 assertEquals(1, nonApps.length); 111 assertTrue(nonApps[0].prefixOrderIndex == Integer.MAX_VALUE); 112 assertEquals(MODE_CHANGING, nonApps[0].mode); 113 } 114 115 @Test 116 public void testLegacyTargetWrapper() { 117 TransitionInfo tinfo = new TransitionInfoBuilder(TRANSIT_CLOSE) 118 .addChange(TRANSIT_CHANGE, FLAG_TRANSLUCENT, 119 createTaskInfo(1 /* taskId */, ACTIVITY_TYPE_STANDARD)).build(); 120 final TransitionInfo.Change change = tinfo.getChanges().get(0); 121 final Rect endBounds = new Rect(40, 60, 140, 200); 122 change.setTaskInfo(createTaskInfo(1 /* taskId */, ACTIVITY_TYPE_HOME)); 123 change.setEndAbsBounds(endBounds); 124 change.setEndRelOffset(0, 0); 125 RemoteAnimationTarget wrapped = TransitionUtil.newTarget( 126 change, 0 /* order */, tinfo, mock(SurfaceControl.Transaction.class), null); 127 assertEquals(ACTIVITY_TYPE_HOME, wrapped.windowConfiguration.getActivityType()); 128 assertEquals(new Rect(0, 0, 100, 140), wrapped.localBounds); 129 assertEquals(endBounds, wrapped.screenSpaceBounds); 130 assertTrue(wrapped.isTranslucent); 131 } 132 133 class TransitionInfoBuilder { 134 final TransitionInfo mInfo; 135 136 TransitionInfoBuilder(@WindowManager.TransitionType int type) { 137 mInfo = new TransitionInfo(type, 0 /* flags */); 138 mInfo.addRootLeash(0, createMockSurface(true /* valid */), 0, 0); 139 } 140 141 TransitionInfoBuilder addChange(@WindowManager.TransitionType int mode, 142 @TransitionInfo.ChangeFlags int flags, ActivityManager.RunningTaskInfo taskInfo) { 143 final TransitionInfo.Change change = 144 new TransitionInfo.Change(null /* token */, createMockSurface(true)); 145 change.setMode(mode); 146 change.setFlags(flags); 147 change.setTaskInfo(taskInfo); 148 change.setDisplayId(0, 0); 149 mInfo.addChange(change); 150 return this; 151 } 152 153 TransitionInfo build() { 154 return mInfo; 155 } 156 } 157 158 private static SurfaceControl createMockSurface(boolean valid) { 159 SurfaceControl sc = mock(SurfaceControl.class); 160 if (valid) { 161 doReturn(true).when(sc).isValid(); 162 doReturn("TestSurface").when(sc).toString(); 163 } 164 return sc; 165 } 166 167 private static ActivityManager.RunningTaskInfo createTaskInfo(int taskId, int activityType) { 168 ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); 169 taskInfo.taskId = taskId; 170 taskInfo.configuration.windowConfiguration.setActivityType(activityType); 171 return taskInfo; 172 } 173 174 } 175