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 com.android.server.wm; 18 19 import static android.view.WindowManager.TRANSIT_CHANGE; 20 21 import static com.android.server.wm.DeviceStateController.DeviceState.FOLDED; 22 import static com.android.server.wm.DeviceStateController.DeviceState.HALF_FOLDED; 23 import static com.android.server.wm.DeviceStateController.DeviceState.OPEN; 24 25 import static com.google.common.truth.Truth.assertThat; 26 27 import static org.mockito.ArgumentMatchers.any; 28 import static org.mockito.ArgumentMatchers.anyInt; 29 import static org.mockito.ArgumentMatchers.eq; 30 import static org.mockito.ArgumentMatchers.isNull; 31 import static org.mockito.Mockito.clearInvocations; 32 import static org.mockito.Mockito.never; 33 import static org.mockito.Mockito.verify; 34 import static org.mockito.Mockito.when; 35 36 import android.animation.ValueAnimator; 37 import android.content.Context; 38 import android.content.res.Resources; 39 import android.graphics.Rect; 40 import android.platform.test.annotations.Presubmit; 41 import android.window.TransitionRequestInfo.DisplayChange; 42 43 import static com.android.internal.R.bool.config_unfoldTransitionEnabled; 44 import static com.android.server.wm.DeviceStateController.DeviceState.REAR; 45 46 import androidx.test.filters.SmallTest; 47 48 import org.junit.After; 49 import org.junit.Before; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 import org.mockito.ArgumentCaptor; 53 import org.mockito.Mock; 54 import org.mockito.MockitoAnnotations; 55 56 /** 57 * Tests for the {@link WindowToken} class. 58 * 59 * Build/Install/Run: 60 * atest WmTests:PhysicalDisplaySwitchTransitionLauncherTest 61 */ 62 @SmallTest 63 @Presubmit 64 @RunWith(WindowTestRunner.class) 65 public class PhysicalDisplaySwitchTransitionLauncherTest extends WindowTestsBase { 66 67 @Mock 68 DisplayContent mDisplayContent; 69 @Mock 70 Context mContext; 71 @Mock 72 Resources mResources; 73 @Mock 74 ActivityTaskManagerService mActivityTaskManagerService; 75 @Mock 76 TransitionController mTransitionController; 77 78 private PhysicalDisplaySwitchTransitionLauncher mTarget; 79 private float mOriginalAnimationScale; 80 81 @Before setUp()82 public void setUp() { 83 MockitoAnnotations.initMocks(this); 84 when(mContext.getResources()).thenReturn(mResources); 85 mTarget = new PhysicalDisplaySwitchTransitionLauncher(mDisplayContent, 86 mActivityTaskManagerService, mContext, mTransitionController); 87 mOriginalAnimationScale = ValueAnimator.getDurationScale(); 88 } 89 90 @After after()91 public void after() { 92 ValueAnimator.setDurationScale(mOriginalAnimationScale); 93 } 94 95 @Test testDisplaySwitchAfterUnfoldToOpen_animationsEnabled_requestsTransition()96 public void testDisplaySwitchAfterUnfoldToOpen_animationsEnabled_requestsTransition() { 97 givenAllAnimationsEnabled(); 98 mTarget.foldStateChanged(FOLDED); 99 100 mTarget.foldStateChanged(OPEN); 101 mTarget.requestDisplaySwitchTransitionIfNeeded( 102 /* displayId= */ 123, 103 /* oldDisplayWidth= */ 100, 104 /* oldDisplayHeight= */ 150, 105 /* newDisplayWidth= */ 200, 106 /* newDisplayHeight= */ 250 107 ); 108 109 ArgumentCaptor<DisplayChange> displayChangeArgumentCaptor = 110 ArgumentCaptor.forClass(DisplayChange.class); 111 verify(mTransitionController).requestTransitionIfNeeded(eq(TRANSIT_CHANGE), /* flags= */ 112 eq(0), eq(mDisplayContent), eq(mDisplayContent), /* remoteTransition= */ isNull(), 113 displayChangeArgumentCaptor.capture()); 114 assertThat(displayChangeArgumentCaptor.getValue().getDisplayId()).isEqualTo(123); 115 assertThat(displayChangeArgumentCaptor.getValue().getStartAbsBounds()).isEqualTo( 116 new Rect(0, 0, 100, 150)); 117 assertThat(displayChangeArgumentCaptor.getValue().getEndAbsBounds()).isEqualTo( 118 new Rect(0, 0, 200, 250)); 119 } 120 121 @Test testDisplaySwitchAfterFolding_animationEnabled_doesNotRequestTransition()122 public void testDisplaySwitchAfterFolding_animationEnabled_doesNotRequestTransition() { 123 givenAllAnimationsEnabled(); 124 mTarget.foldStateChanged(OPEN); 125 126 mTarget.foldStateChanged(FOLDED); 127 requestDisplaySwitch(); 128 129 assertTransitionNotRequested(); 130 } 131 132 @Test testDisplaySwitchAfterUnfoldingToHalf_animationEnabled_requestsTransition()133 public void testDisplaySwitchAfterUnfoldingToHalf_animationEnabled_requestsTransition() { 134 givenAllAnimationsEnabled(); 135 mTarget.foldStateChanged(FOLDED); 136 137 mTarget.foldStateChanged(HALF_FOLDED); 138 requestDisplaySwitch(); 139 140 assertTransitionRequested(); 141 } 142 143 @Test testDisplaySwitchSecondTimeAfterUnfolding_animationEnabled_noTransition()144 public void testDisplaySwitchSecondTimeAfterUnfolding_animationEnabled_noTransition() { 145 givenAllAnimationsEnabled(); 146 mTarget.foldStateChanged(FOLDED); 147 mTarget.foldStateChanged(OPEN); 148 requestDisplaySwitch(); 149 clearInvocations(mTransitionController); 150 151 requestDisplaySwitch(); 152 153 assertTransitionNotRequested(); 154 } 155 156 157 @Test testDisplaySwitchAfterGoingToRearAndBack_animationEnabled_noTransition()158 public void testDisplaySwitchAfterGoingToRearAndBack_animationEnabled_noTransition() { 159 givenAllAnimationsEnabled(); 160 mTarget.foldStateChanged(OPEN); 161 162 mTarget.foldStateChanged(REAR); 163 mTarget.foldStateChanged(OPEN); 164 requestDisplaySwitch(); 165 166 assertTransitionNotRequested(); 167 } 168 169 @Test testDisplaySwitchAfterUnfoldingAndFolding_animationEnabled_noTransition()170 public void testDisplaySwitchAfterUnfoldingAndFolding_animationEnabled_noTransition() { 171 givenAllAnimationsEnabled(); 172 mTarget.foldStateChanged(FOLDED); 173 mTarget.foldStateChanged(OPEN); 174 // No request display switch event (simulate very fast fold after unfold, even before 175 // the displays switched) 176 mTarget.foldStateChanged(FOLDED); 177 178 requestDisplaySwitch(); 179 180 assertTransitionNotRequested(); 181 } 182 183 @Test testDisplaySwitch_whenShellTransitionsNotEnabled_noTransition()184 public void testDisplaySwitch_whenShellTransitionsNotEnabled_noTransition() { 185 givenAllAnimationsEnabled(); 186 givenShellTransitionsEnabled(false); 187 mTarget.foldStateChanged(FOLDED); 188 189 mTarget.foldStateChanged(OPEN); 190 requestDisplaySwitch(); 191 192 assertTransitionNotRequested(); 193 } 194 195 @Test testDisplaySwitch_whenAnimationsDisabled_noTransition()196 public void testDisplaySwitch_whenAnimationsDisabled_noTransition() { 197 givenAllAnimationsEnabled(); 198 givenAnimationsEnabled(false); 199 mTarget.foldStateChanged(FOLDED); 200 201 mTarget.foldStateChanged(OPEN); 202 requestDisplaySwitch(); 203 204 assertTransitionNotRequested(); 205 } 206 207 @Test testDisplaySwitch_whenUnfoldAnimationDisabled_noTransition()208 public void testDisplaySwitch_whenUnfoldAnimationDisabled_noTransition() { 209 givenAllAnimationsEnabled(); 210 givenUnfoldTransitionEnabled(false); 211 mTarget.foldStateChanged(FOLDED); 212 213 mTarget.foldStateChanged(OPEN); 214 requestDisplaySwitch(); 215 216 assertTransitionNotRequested(); 217 } 218 219 @Test testDisplaySwitch_whenNoContentInDisplayContent_noTransition()220 public void testDisplaySwitch_whenNoContentInDisplayContent_noTransition() { 221 givenAllAnimationsEnabled(); 222 givenDisplayContentHasContent(false); 223 mTarget.foldStateChanged(FOLDED); 224 225 mTarget.foldStateChanged(OPEN); 226 requestDisplaySwitch(); 227 228 assertTransitionNotRequested(); 229 } 230 assertTransitionRequested()231 private void assertTransitionRequested() { 232 verify(mTransitionController).requestTransitionIfNeeded(anyInt(), anyInt(), any(), any(), 233 any(), any()); 234 } 235 assertTransitionNotRequested()236 private void assertTransitionNotRequested() { 237 verify(mTransitionController, never()).requestTransitionIfNeeded(anyInt(), anyInt(), any(), 238 any(), any(), any()); 239 } 240 requestDisplaySwitch()241 private void requestDisplaySwitch() { 242 mTarget.requestDisplaySwitchTransitionIfNeeded( 243 /* displayId= */ 123, 244 /* oldDisplayWidth= */ 100, 245 /* oldDisplayHeight= */ 150, 246 /* newDisplayWidth= */ 200, 247 /* newDisplayHeight= */ 250 248 ); 249 } 250 givenAllAnimationsEnabled()251 private void givenAllAnimationsEnabled() { 252 givenAnimationsEnabled(true); 253 givenUnfoldTransitionEnabled(true); 254 givenShellTransitionsEnabled(true); 255 givenDisplayContentHasContent(true); 256 } 257 givenUnfoldTransitionEnabled(boolean enabled)258 private void givenUnfoldTransitionEnabled(boolean enabled) { 259 when(mResources.getBoolean(config_unfoldTransitionEnabled)).thenReturn(enabled); 260 } 261 givenAnimationsEnabled(boolean enabled)262 private void givenAnimationsEnabled(boolean enabled) { 263 ValueAnimator.setDurationScale(enabled ? 1.0f : 0.0f); 264 } 265 givenShellTransitionsEnabled(boolean enabled)266 private void givenShellTransitionsEnabled(boolean enabled) { 267 when(mTransitionController.isShellTransitionsEnabled()).thenReturn(enabled); 268 } 269 givenDisplayContentHasContent(boolean hasContent)270 private void givenDisplayContentHasContent(boolean hasContent) { 271 when(mDisplayContent.getLastHasContent()).thenReturn(hasContent); 272 } 273 } 274