1 /* 2 * Copyright (C) 2020 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.accessibility; 18 19 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertNotNull; 23 import static org.junit.Assert.assertTrue; 24 import static org.mockito.ArgumentMatchers.any; 25 import static org.mockito.ArgumentMatchers.anyBoolean; 26 import static org.mockito.ArgumentMatchers.anyFloat; 27 import static org.mockito.ArgumentMatchers.eq; 28 import static org.mockito.Mockito.atLeast; 29 import static org.mockito.Mockito.never; 30 import static org.mockito.Mockito.spy; 31 import static org.mockito.Mockito.times; 32 import static org.mockito.Mockito.verify; 33 34 import android.animation.ValueAnimator; 35 import android.annotation.Nullable; 36 import android.content.Context; 37 import android.graphics.Rect; 38 import android.os.Handler; 39 import android.os.RemoteException; 40 import android.platform.test.annotations.RequiresFlagsDisabled; 41 import android.platform.test.annotations.RequiresFlagsEnabled; 42 import android.platform.test.flag.junit.CheckFlagsRule; 43 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 44 import android.testing.AndroidTestingRunner; 45 import android.view.SurfaceControl; 46 import android.view.SurfaceControlViewHost; 47 import android.view.View; 48 import android.view.WindowManager; 49 import android.view.WindowManagerGlobal; 50 import android.view.accessibility.IRemoteMagnificationAnimationCallback; 51 import android.view.animation.AccelerateInterpolator; 52 import android.window.InputTransferToken; 53 54 import androidx.test.filters.LargeTest; 55 56 import com.android.internal.graphics.SfVsyncFrameCallbackProvider; 57 import com.android.systemui.Flags; 58 import com.android.systemui.SysuiTestCase; 59 import com.android.systemui.animation.AnimatorTestRule; 60 import com.android.systemui.model.SysUiState; 61 import com.android.systemui.res.R; 62 import com.android.systemui.util.settings.SecureSettings; 63 64 import org.junit.After; 65 import org.junit.Before; 66 import org.junit.Rule; 67 import org.junit.Test; 68 import org.junit.runner.RunWith; 69 import org.mockito.Answers; 70 import org.mockito.ArgumentCaptor; 71 import org.mockito.Mock; 72 import org.mockito.Mockito; 73 import org.mockito.MockitoAnnotations; 74 75 import java.util.ArrayList; 76 import java.util.List; 77 import java.util.concurrent.atomic.AtomicReference; 78 import java.util.function.Supplier; 79 80 @LargeTest 81 @RunWith(AndroidTestingRunner.class) 82 public class WindowMagnificationAnimationControllerTest extends SysuiTestCase { 83 84 @Rule 85 public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule(this); 86 @Rule 87 public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 88 private static final float DEFAULT_SCALE = 4.0f; 89 private static final float DEFAULT_CENTER_X = 400.0f; 90 private static final float DEFAULT_CENTER_Y = 500.0f; 91 92 private AtomicReference<Float> mCurrentScale = new AtomicReference<>((float) 0); 93 private AtomicReference<Float> mCurrentCenterX = new AtomicReference<>((float) 0); 94 private AtomicReference<Float> mCurrentCenterY = new AtomicReference<>((float) 0); 95 private ArgumentCaptor<Float> mScaleCaptor = ArgumentCaptor.forClass(Float.class); 96 private ArgumentCaptor<Float> mCenterXCaptor = ArgumentCaptor.forClass(Float.class); 97 private ArgumentCaptor<Float> mCenterYCaptor = ArgumentCaptor.forClass(Float.class); 98 private final ArgumentCaptor<Float> mOffsetXCaptor = ArgumentCaptor.forClass(Float.class); 99 private final ArgumentCaptor<Float> mOffsetYCaptor = ArgumentCaptor.forClass(Float.class); 100 101 @Mock 102 Handler mHandler; 103 @Mock 104 SfVsyncFrameCallbackProvider mSfVsyncFrameProvider; 105 @Mock 106 WindowMagnifierCallback mWindowMagnifierCallback; 107 @Mock 108 IRemoteMagnificationAnimationCallback mAnimationCallback; 109 @Mock 110 IRemoteMagnificationAnimationCallback mAnimationCallback2; 111 @Mock(answer = Answers.RETURNS_SELF) 112 SysUiState mSysUiState; 113 @Mock 114 SecureSettings mSecureSettings; 115 private SpyWindowMagnificationController mController; 116 private WindowMagnificationController mSpyController; 117 private WindowMagnificationAnimationController mWindowMagnificationAnimationController; 118 119 private long mWaitAnimationDuration; 120 private long mWaitPartialAnimationDuration; 121 122 private TestableWindowManager mWindowManager; 123 private ValueAnimator mValueAnimator; 124 // This list contains all SurfaceControlViewHosts created during a given test. If the 125 // magnification window is recreated during a test, the list will contain more than a single 126 // element. 127 private List<SurfaceControlViewHost> mSurfaceControlViewHosts = new ArrayList<>(); 128 // The most recently created SurfaceControlViewHost. 129 private SurfaceControlViewHost mSurfaceControlViewHost; 130 private SurfaceControl.Transaction mTransaction; 131 132 @Before setUp()133 public void setUp() throws Exception { 134 MockitoAnnotations.initMocks(this); 135 final WindowManager wm = mContext.getSystemService(WindowManager.class); 136 mWindowManager = spy(new TestableWindowManager(wm)); 137 mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager); 138 139 // Using the animation duration in WindowMagnificationAnimationController for testing. 140 mWaitAnimationDuration = mContext.getResources() 141 .getInteger(com.android.internal.R.integer.config_longAnimTime); 142 mWaitPartialAnimationDuration = mWaitAnimationDuration / 2; 143 144 mValueAnimator = newValueAnimator(); 145 mWindowMagnificationAnimationController = new WindowMagnificationAnimationController( 146 mContext, mValueAnimator); 147 148 Supplier<SurfaceControlViewHost> scvhSupplier = () -> { 149 mSurfaceControlViewHost = spy(new SurfaceControlViewHost( 150 mContext, mContext.getDisplay(), new InputTransferToken(), 151 "WindowMagnification")); 152 mSurfaceControlViewHosts.add(mSurfaceControlViewHost); 153 return mSurfaceControlViewHost; 154 }; 155 156 mTransaction = spy(new SurfaceControl.Transaction()); 157 mController = new SpyWindowMagnificationController( 158 mContext, 159 mHandler, 160 mWindowMagnificationAnimationController, 161 /* mirrorWindowControl= */ null, 162 mTransaction, 163 mWindowMagnifierCallback, 164 mSysUiState, 165 mSecureSettings, 166 scvhSupplier, 167 mSfVsyncFrameProvider); 168 169 mSpyController = mController.getSpyController(); 170 } 171 172 @After tearDown()173 public void tearDown() throws Exception { 174 getInstrumentation().runOnMainSync(() -> { 175 mController.deleteWindowMagnification(); 176 }); 177 } 178 179 @Test enableWindowMagnification_disabled_expectedValuesAndInvokeCallback()180 public void enableWindowMagnification_disabled_expectedValuesAndInvokeCallback() 181 throws RemoteException { 182 enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback); 183 184 verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal( 185 mScaleCaptor.capture(), 186 mCenterXCaptor.capture(), mCenterYCaptor.capture(), 187 mOffsetXCaptor.capture(), mOffsetYCaptor.capture()); 188 verifyStartValue(mScaleCaptor, 1.0f); 189 verifyStartValue(mCenterXCaptor, DEFAULT_CENTER_X); 190 verifyStartValue(mCenterYCaptor, DEFAULT_CENTER_Y); 191 verifyStartValue(mOffsetXCaptor, 0f); 192 verifyStartValue(mOffsetYCaptor, 0f); 193 verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y); 194 verify(mAnimationCallback).onResult(true); 195 } 196 197 @Test enableWindowMagnificationWithoutCallback_disabled_expectedValues()198 public void enableWindowMagnificationWithoutCallback_disabled_expectedValues() { 199 enableWindowMagnificationWithoutAnimation(); 200 201 verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y); 202 } 203 204 @Test enableWindowMagnificationWithoutCallback_enabled_expectedValues()205 public void enableWindowMagnificationWithoutCallback_enabled_expectedValues() { 206 enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback); 207 final float targetScale = DEFAULT_SCALE + 1.0f; 208 final float targetCenterX = DEFAULT_CENTER_X + 100; 209 final float targetCenterY = DEFAULT_CENTER_Y + 100; 210 211 enableWindowMagnificationWithoutAnimation(targetScale, targetCenterX, targetCenterY); 212 213 verifyFinalSpec(targetScale, targetCenterX, targetCenterY); 214 } 215 216 @Test enableWindowMagnificationWithScaleOne_disabled_NoAnimationAndInvokeCallback()217 public void enableWindowMagnificationWithScaleOne_disabled_NoAnimationAndInvokeCallback() 218 throws RemoteException { 219 enableWindowMagnificationAndWaitAnimating( 220 mWaitAnimationDuration, /* targetScale= */ 1.0f, 221 DEFAULT_CENTER_X, DEFAULT_CENTER_Y, mAnimationCallback); 222 223 verify(mSpyController).updateWindowMagnificationInternal(1.0f, DEFAULT_CENTER_X, 224 DEFAULT_CENTER_Y, 0f, 0f); 225 verify(mAnimationCallback).onResult(true); 226 } 227 228 @Test enableWindowMagnification_enabling_expectedValuesAndInvokeCallback()229 public void enableWindowMagnification_enabling_expectedValuesAndInvokeCallback() 230 throws RemoteException { 231 enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration, 232 mAnimationCallback); 233 final float targetScale = DEFAULT_SCALE + 1.0f; 234 final float targetCenterX = DEFAULT_CENTER_X + 100; 235 final float targetCenterY = DEFAULT_CENTER_Y + 100; 236 237 resetMockObjects(); 238 getInstrumentation().runOnMainSync(() -> { 239 mWindowMagnificationAnimationController.enableWindowMagnification(targetScale, 240 targetCenterX, targetCenterY, mAnimationCallback2); 241 mCurrentScale.set(mController.getScale()); 242 mCurrentCenterX.set(mController.getCenterX()); 243 mCurrentCenterY.set(mController.getCenterY()); 244 advanceTimeBy(mWaitAnimationDuration); 245 }); 246 247 verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal( 248 mScaleCaptor.capture(), 249 mCenterXCaptor.capture(), mCenterYCaptor.capture(), 250 mOffsetXCaptor.capture(), mOffsetYCaptor.capture()); 251 verifyStartValue(mScaleCaptor, mCurrentScale.get()); 252 verifyStartValue(mCenterXCaptor, mCurrentCenterX.get()); 253 verifyStartValue(mCenterYCaptor, mCurrentCenterY.get()); 254 verifyStartValue(mOffsetXCaptor, 0f); 255 verifyStartValue(mOffsetYCaptor, 0f); 256 verifyFinalSpec(targetScale, targetCenterX, targetCenterY); 257 verify(mAnimationCallback).onResult(false); 258 verify(mAnimationCallback2).onResult(true); 259 } 260 261 @Test enableWindowMagnificationWithUnchanged_enabling_expectedValuesToDefault()262 public void enableWindowMagnificationWithUnchanged_enabling_expectedValuesToDefault() 263 throws RemoteException { 264 enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration, 265 mAnimationCallback); 266 267 enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, Float.NaN, 268 Float.NaN, Float.NaN, mAnimationCallback2); 269 270 // The callback in 2nd enableWindowMagnification will return true 271 verify(mAnimationCallback2).onResult(true); 272 // The callback in 1st enableWindowMagnification will return false 273 verify(mAnimationCallback).onResult(false); 274 verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y); 275 } 276 277 @RequiresFlagsEnabled(Flags.FLAG_CREATE_WINDOWLESS_WINDOW_MAGNIFIER) 278 @Test 279 public void enableWindowMagnificationScaleOne_enabledAndWindowlessFlagOn_AnimationAndCallbackTrue()280 enableWindowMagnificationScaleOne_enabledAndWindowlessFlagOn_AnimationAndCallbackTrue() 281 throws RemoteException { 282 enableWindowMagnificationWithoutAnimation(); 283 284 // Wait for Rects updated. 285 waitForIdleSync(); 286 View mirrorView = mSurfaceControlViewHost.getView(); 287 final float targetScale = 1.0f; 288 // Move the magnifier to the top left corner, within the boundary 289 final float targetCenterX = mirrorView.getWidth() / 2.0f; 290 final float targetCenterY = mirrorView.getHeight() / 2.0f; 291 292 Mockito.reset(mSpyController); 293 getInstrumentation().runOnMainSync(() -> { 294 mWindowMagnificationAnimationController.enableWindowMagnification(targetScale, 295 targetCenterX, targetCenterY, mAnimationCallback); 296 mCurrentScale.set(mController.getScale()); 297 mCurrentCenterX.set(mController.getCenterX()); 298 mCurrentCenterY.set(mController.getCenterY()); 299 advanceTimeBy(mWaitAnimationDuration); 300 }); 301 302 verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal( 303 mScaleCaptor.capture(), 304 mCenterXCaptor.capture(), mCenterYCaptor.capture(), 305 mOffsetXCaptor.capture(), mOffsetYCaptor.capture()); 306 verifyStartValue(mScaleCaptor, mCurrentScale.get()); 307 verifyStartValue(mCenterXCaptor, mCurrentCenterX.get()); 308 verifyStartValue(mCenterYCaptor, mCurrentCenterY.get()); 309 verifyStartValue(mOffsetXCaptor, 0f); 310 verifyStartValue(mOffsetYCaptor, 0f); 311 312 verifyFinalSpec(targetScale, targetCenterX, targetCenterY); 313 314 verify(mAnimationCallback).onResult(true); 315 assertEquals(WindowMagnificationAnimationController.STATE_ENABLED, 316 mWindowMagnificationAnimationController.getState()); 317 } 318 319 @RequiresFlagsDisabled(Flags.FLAG_CREATE_WINDOWLESS_WINDOW_MAGNIFIER) 320 @Test 321 public void enableWindowMagnificationScaleOne_enabledAndWindowlessFlagOff_AnimationAndCallbackTrue()322 enableWindowMagnificationScaleOne_enabledAndWindowlessFlagOff_AnimationAndCallbackTrue() 323 throws RemoteException { 324 enableWindowMagnificationWithoutAnimation(); 325 326 // Wait for Rects updated. 327 waitForIdleSync(); 328 View mirrorView = mWindowManager.getAttachedView(); 329 final float targetScale = 1.0f; 330 // Move the magnifier to the top left corner, within the boundary 331 final float targetCenterX = mirrorView.getWidth() / 2.0f; 332 final float targetCenterY = mirrorView.getHeight() / 2.0f; 333 334 Mockito.reset(mSpyController); 335 getInstrumentation().runOnMainSync(() -> { 336 mWindowMagnificationAnimationController.enableWindowMagnification(targetScale, 337 targetCenterX, targetCenterY, mAnimationCallback); 338 mCurrentScale.set(mController.getScale()); 339 mCurrentCenterX.set(mController.getCenterX()); 340 mCurrentCenterY.set(mController.getCenterY()); 341 advanceTimeBy(mWaitAnimationDuration); 342 }); 343 344 verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal( 345 mScaleCaptor.capture(), 346 mCenterXCaptor.capture(), mCenterYCaptor.capture(), 347 mOffsetXCaptor.capture(), mOffsetYCaptor.capture()); 348 verifyStartValue(mScaleCaptor, mCurrentScale.get()); 349 verifyStartValue(mCenterXCaptor, mCurrentCenterX.get()); 350 verifyStartValue(mCenterYCaptor, mCurrentCenterY.get()); 351 verifyStartValue(mOffsetXCaptor, 0f); 352 verifyStartValue(mOffsetYCaptor, 0f); 353 354 verifyFinalSpec(targetScale, targetCenterX, targetCenterY); 355 356 verify(mAnimationCallback).onResult(true); 357 assertEquals(WindowMagnificationAnimationController.STATE_ENABLED, 358 mWindowMagnificationAnimationController.getState()); 359 } 360 361 @Test enableWindowMagnificationWithScaleLessThanOne_enabled_AnimationAndInvokeCallback()362 public void enableWindowMagnificationWithScaleLessThanOne_enabled_AnimationAndInvokeCallback() 363 throws RemoteException { 364 enableWindowMagnificationWithoutAnimation(); 365 366 final float targetScale = 0.99f; 367 final float targetCenterX = DEFAULT_CENTER_X + 100; 368 final float targetCenterY = DEFAULT_CENTER_Y + 100; 369 370 Mockito.reset(mSpyController); 371 getInstrumentation().runOnMainSync(() -> { 372 mWindowMagnificationAnimationController.enableWindowMagnification(targetScale, 373 targetCenterX, targetCenterY, mAnimationCallback); 374 mCurrentScale.set(mController.getScale()); 375 mCurrentCenterX.set(mController.getCenterX()); 376 mCurrentCenterY.set(mController.getCenterY()); 377 advanceTimeBy(mWaitAnimationDuration); 378 }); 379 380 verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal( 381 mScaleCaptor.capture(), 382 mCenterXCaptor.capture(), mCenterYCaptor.capture(), 383 mOffsetXCaptor.capture(), mOffsetYCaptor.capture()); 384 verifyStartValue(mScaleCaptor, mCurrentScale.get()); 385 verifyStartValue(mCenterXCaptor, mCurrentCenterX.get()); 386 verifyStartValue(mCenterYCaptor, mCurrentCenterY.get()); 387 verifyStartValue(mOffsetXCaptor, 0f); 388 verifyStartValue(mOffsetYCaptor, 0f); 389 // It presents the window magnification is disabled. 390 verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); 391 392 verify(mAnimationCallback).onResult(true); 393 assertEquals(WindowMagnificationAnimationController.STATE_DISABLED, 394 mWindowMagnificationAnimationController.getState()); 395 } 396 397 @Test 398 public void enableWindowMagnificationWithScaleLessThanOneAndWithoutCallBack_enabled_expectedValues()399 enableWindowMagnificationWithScaleLessThanOneAndWithoutCallBack_enabled_expectedValues() 400 throws RemoteException { 401 enableWindowMagnificationWithoutAnimation(); 402 403 final float targetScale = 0.99f; 404 final float targetCenterX = DEFAULT_CENTER_X + 100; 405 final float targetCenterY = DEFAULT_CENTER_Y + 100; 406 407 Mockito.reset(mSpyController); 408 enableWindowMagnificationWithoutAnimation(targetScale, targetCenterX, targetCenterY); 409 410 verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); 411 assertEquals(WindowMagnificationAnimationController.STATE_DISABLED, 412 mWindowMagnificationAnimationController.getState()); 413 } 414 415 @Test 416 public void enableMagnificationWithoutCallback_enabling_expectedValuesAndInvokeFormerCallback()417 enableMagnificationWithoutCallback_enabling_expectedValuesAndInvokeFormerCallback() 418 throws RemoteException { 419 enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration, 420 mAnimationCallback); 421 final float targetScale = DEFAULT_SCALE - 1.0f; 422 final float targetCenterX = DEFAULT_CENTER_X + 100; 423 final float targetCenterY = DEFAULT_CENTER_Y + 100; 424 425 Mockito.reset(mSpyController); 426 enableWindowMagnificationWithoutAnimation(targetScale, targetCenterX, targetCenterY); 427 428 verifyFinalSpec(targetScale, targetCenterX, targetCenterY); 429 verify(mAnimationCallback).onResult(false); 430 } 431 432 @Test enableWindowMagnificationWithSameSpec_enabling_NoAnimationAndInvokeCallback()433 public void enableWindowMagnificationWithSameSpec_enabling_NoAnimationAndInvokeCallback() 434 throws RemoteException { 435 enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration, 436 mAnimationCallback); 437 438 Mockito.reset(mSpyController); 439 enableWindowMagnificationAndWaitAnimating( 440 mWaitAnimationDuration, Float.NaN, Float.NaN, Float.NaN, mAnimationCallback2); 441 442 verify(mSpyController, never()).updateWindowMagnificationInternal(anyFloat(), anyFloat(), 443 anyFloat()); 444 verify(mAnimationCallback).onResult(false); 445 verify(mAnimationCallback2).onResult(true); 446 } 447 448 @Test enableWindowMagnification_disabling_expectedValuesAndInvokeCallback()449 public void enableWindowMagnification_disabling_expectedValuesAndInvokeCallback() 450 throws RemoteException { 451 enableWindowMagnificationWithoutAnimation(); 452 deleteWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration, 453 mAnimationCallback); 454 final float targetScale = DEFAULT_SCALE + 1.0f; 455 final float targetCenterX = DEFAULT_CENTER_X + 100; 456 final float targetCenterY = DEFAULT_CENTER_Y + 100; 457 458 Mockito.reset(mSpyController); 459 getInstrumentation().runOnMainSync(() -> { 460 mWindowMagnificationAnimationController.enableWindowMagnification(targetScale, 461 targetCenterX, targetCenterY, mAnimationCallback2); 462 mCurrentScale.set(mController.getScale()); 463 mCurrentCenterX.set(mController.getCenterX()); 464 mCurrentCenterY.set(mController.getCenterY()); 465 }); 466 467 // Current spec shouldn't match given spec. 468 verify(mAnimationCallback2, never()).onResult(anyBoolean()); 469 verify(mAnimationCallback).onResult(false); 470 471 getInstrumentation().runOnMainSync(() -> { 472 // ValueAnimator.reverse() could not work correctly with the AnimatorTestRule since it 473 // is using SystemClock in reverse() (b/305731398). Therefore, we call end() on the 474 // animator directly to verify the result of animation is correct instead of querying 475 // the animation frame at a specific timing. 476 mValueAnimator.end(); 477 }); 478 479 // Verify the method is called in 480 // {@link ValueAnimator.AnimatorUpdateListener#onAnimationUpdate} once 481 verify(mSpyController).updateWindowMagnificationInternal( 482 mScaleCaptor.capture(), 483 mCenterXCaptor.capture(), mCenterYCaptor.capture(), 484 mOffsetXCaptor.capture(), mOffsetYCaptor.capture()); 485 486 // The animation is playing forwards, so we only check the animated values are greater than 487 // the current one. (Asserting the first captured scale) 488 assertTrue(mScaleCaptor.getAllValues().get(0) > mCurrentScale.get()); 489 // The last captured scale equalsto the targetScale when we enable window magnification. 490 assertEquals(targetScale, mScaleCaptor.getValue(), 0f); 491 assertTrue(mCenterXCaptor.getAllValues().get(0) > mCurrentCenterX.get()); 492 assertEquals(targetCenterX, mCenterXCaptor.getValue(), 0f); 493 assertTrue(mCenterYCaptor.getAllValues().get(0) > mCurrentCenterY.get()); 494 assertEquals(targetCenterY, mCenterYCaptor.getValue(), 0f); 495 verifyFinalSpec(targetScale, targetCenterX, targetCenterY); 496 verify(mAnimationCallback2).onResult(true); 497 } 498 499 @Test 500 public void enableMagnificationWithoutCallback_disabling_expectedValuesAndInvokeFormerCallback()501 enableMagnificationWithoutCallback_disabling_expectedValuesAndInvokeFormerCallback() 502 throws RemoteException { 503 enableWindowMagnificationWithoutAnimation(); 504 deleteWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration, 505 mAnimationCallback); 506 final float targetScale = DEFAULT_SCALE + 1.0f; 507 final float targetCenterX = DEFAULT_CENTER_X + 100; 508 final float targetCenterY = DEFAULT_CENTER_Y + 100; 509 510 Mockito.reset(mSpyController); 511 enableWindowMagnificationWithoutAnimation(targetScale, targetCenterX, targetCenterY); 512 513 verify(mAnimationCallback).onResult(false); 514 verifyFinalSpec(targetScale, targetCenterX, targetCenterY); 515 } 516 517 @Test enableWindowMagnificationWithSameSpec_disabling_NoAnimationAndInvokeCallback()518 public void enableWindowMagnificationWithSameSpec_disabling_NoAnimationAndInvokeCallback() 519 throws RemoteException { 520 enableWindowMagnificationWithoutAnimation(); 521 deleteWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration, 522 mAnimationCallback); 523 524 Mockito.reset(mSpyController); 525 enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, Float.NaN, 526 Float.NaN, Float.NaN, mAnimationCallback2); 527 528 verify(mSpyController, never()).updateWindowMagnificationInternal(anyFloat(), anyFloat(), 529 anyFloat()); 530 verify(mSpyController, never()).deleteWindowMagnification(); 531 verify(mAnimationCallback).onResult(false); 532 verify(mAnimationCallback2).onResult(true); 533 } 534 535 @Test enableWindowMagnification_enabled_expectedValuesAndInvokeCallback()536 public void enableWindowMagnification_enabled_expectedValuesAndInvokeCallback() 537 throws RemoteException { 538 enableWindowMagnificationWithoutAnimation(); 539 final float targetScale = DEFAULT_SCALE + 1.0f; 540 final float targetCenterX = DEFAULT_CENTER_X + 100; 541 final float targetCenterY = DEFAULT_CENTER_Y + 100; 542 543 Mockito.reset(mSpyController); 544 getInstrumentation().runOnMainSync(() -> { 545 mWindowMagnificationAnimationController.enableWindowMagnification(targetScale, 546 targetCenterX, targetCenterY, mAnimationCallback2); 547 mCurrentScale.set(mController.getScale()); 548 mCurrentCenterX.set(mController.getCenterX()); 549 mCurrentCenterY.set(mController.getCenterY()); 550 advanceTimeBy(mWaitAnimationDuration); 551 }); 552 553 verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal( 554 mScaleCaptor.capture(), 555 mCenterXCaptor.capture(), mCenterYCaptor.capture(), 556 mOffsetXCaptor.capture(), mOffsetYCaptor.capture()); 557 verifyStartValue(mScaleCaptor, mCurrentScale.get()); 558 verifyStartValue(mCenterXCaptor, mCurrentCenterX.get()); 559 verifyStartValue(mCenterYCaptor, mCurrentCenterY.get()); 560 verifyStartValue(mOffsetXCaptor, 0f); 561 verifyStartValue(mOffsetYCaptor, 0f); 562 verifyFinalSpec(targetScale, targetCenterX, targetCenterY); 563 verify(mAnimationCallback2).onResult(true); 564 } 565 566 @RequiresFlagsEnabled(Flags.FLAG_CREATE_WINDOWLESS_WINDOW_MAGNIFIER) 567 @Test enableWindowMagnificationWithOffset_windowlessFlagOn_expectedValues()568 public void enableWindowMagnificationWithOffset_windowlessFlagOn_expectedValues() { 569 final float offsetRatio = -0.1f; 570 final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds()); 571 572 Mockito.reset(mSpyController); 573 getInstrumentation().runOnMainSync(() -> { 574 mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE, 575 windowBounds.exactCenterX(), windowBounds.exactCenterY(), 576 offsetRatio, offsetRatio, mAnimationCallback); 577 advanceTimeBy(mWaitAnimationDuration); 578 }); 579 // Wait for Rects update 580 waitForIdleSync(); 581 582 final int mirrorSurfaceMargin = mContext.getResources().getDimensionPixelSize( 583 R.dimen.magnification_mirror_surface_margin); 584 final int defaultMagnificationWindowSize = 585 mController.getMagnificationWindowSizeFromIndex( 586 WindowMagnificationSettings.MagnificationSize.MEDIUM); 587 final int defaultMagnificationFrameSize = 588 defaultMagnificationWindowSize - 2 * mirrorSurfaceMargin; 589 final int expectedOffset = (int) (defaultMagnificationFrameSize / 2 * offsetRatio); 590 591 final float expectedX = (int) (windowBounds.exactCenterX() + expectedOffset 592 - defaultMagnificationWindowSize / 2); 593 final float expectedY = (int) (windowBounds.exactCenterY() + expectedOffset 594 - defaultMagnificationWindowSize / 2); 595 596 // This is called 4 times when (1) first creating WindowlessMirrorWindow (2) SurfaceView is 597 // created and we place the mirrored content as a child of the SurfaceView 598 // (3) the animation starts (4) the animation updates 599 verify(mTransaction, times(4)) 600 .setPosition(any(SurfaceControl.class), eq(expectedX), eq(expectedY)); 601 } 602 603 @RequiresFlagsDisabled(Flags.FLAG_CREATE_WINDOWLESS_WINDOW_MAGNIFIER) 604 @Test enableWindowMagnificationWithOffset_windowlessFlagOff_expectedValues()605 public void enableWindowMagnificationWithOffset_windowlessFlagOff_expectedValues() { 606 final float offsetRatio = -0.1f; 607 final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds()); 608 609 Mockito.reset(mSpyController); 610 getInstrumentation().runOnMainSync(() -> { 611 mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE, 612 windowBounds.exactCenterX(), windowBounds.exactCenterY(), 613 offsetRatio, offsetRatio, mAnimationCallback); 614 advanceTimeBy(mWaitAnimationDuration); 615 }); 616 617 // Wait for Rects update 618 waitForIdleSync(); 619 final View attachedView = mWindowManager.getAttachedView(); 620 assertNotNull(attachedView); 621 final Rect mirrorViewBound = new Rect(); 622 final View mirrorView = attachedView.findViewById(R.id.surface_view); 623 assertNotNull(mirrorView); 624 mirrorView.getBoundsOnScreen(mirrorViewBound); 625 626 assertEquals((int) (offsetRatio * mirrorViewBound.width() / 2), 627 (int) (mirrorViewBound.exactCenterX() - windowBounds.exactCenterX())); 628 assertEquals((int) (offsetRatio * mirrorViewBound.height() / 2), 629 (int) (mirrorViewBound.exactCenterY() - windowBounds.exactCenterY())); 630 } 631 632 @Test moveWindowMagnifierToPosition_enabled_expectedValues()633 public void moveWindowMagnifierToPosition_enabled_expectedValues() throws RemoteException { 634 final float targetCenterX = DEFAULT_CENTER_X + 100; 635 final float targetCenterY = DEFAULT_CENTER_Y + 100; 636 enableWindowMagnificationWithoutAnimation(); 637 638 getInstrumentation().runOnMainSync(() -> { 639 mWindowMagnificationAnimationController.moveWindowMagnifierToPosition( 640 targetCenterX, targetCenterY, mAnimationCallback); 641 advanceTimeBy(mWaitAnimationDuration); 642 }); 643 644 verify(mAnimationCallback).onResult(true); 645 verify(mAnimationCallback, never()).onResult(false); 646 verifyFinalSpec(DEFAULT_SCALE, targetCenterX, targetCenterY); 647 } 648 649 @Test moveWindowMagnifierToPositionMultipleTimes_enabled_expectedValuesToLastOne()650 public void moveWindowMagnifierToPositionMultipleTimes_enabled_expectedValuesToLastOne() 651 throws RemoteException { 652 enableWindowMagnificationWithoutAnimation(); 653 654 getInstrumentation().runOnMainSync(() -> { 655 mWindowMagnificationAnimationController.moveWindowMagnifierToPosition( 656 DEFAULT_CENTER_X + 10, DEFAULT_CENTER_Y + 10, mAnimationCallback); 657 mWindowMagnificationAnimationController.moveWindowMagnifierToPosition( 658 DEFAULT_CENTER_X + 20, DEFAULT_CENTER_Y + 20, mAnimationCallback); 659 mWindowMagnificationAnimationController.moveWindowMagnifierToPosition( 660 DEFAULT_CENTER_X + 30, DEFAULT_CENTER_Y + 30, mAnimationCallback); 661 mWindowMagnificationAnimationController.moveWindowMagnifierToPosition( 662 DEFAULT_CENTER_X + 40, DEFAULT_CENTER_Y + 40, mAnimationCallback2); 663 advanceTimeBy(mWaitAnimationDuration); 664 }); 665 666 // only the last one callback will return true 667 verify(mAnimationCallback2).onResult(true); 668 // the others will return false 669 verify(mAnimationCallback, times(3)).onResult(false); 670 verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + 40, DEFAULT_CENTER_Y + 40); 671 } 672 673 @Test moveWindowMagnifierToPosition_enabling_expectedValuesToLastOne()674 public void moveWindowMagnifierToPosition_enabling_expectedValuesToLastOne() 675 throws RemoteException { 676 final float targetCenterX = DEFAULT_CENTER_X + 100; 677 final float targetCenterY = DEFAULT_CENTER_Y + 100; 678 679 enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration, 680 mAnimationCallback); 681 682 getInstrumentation().runOnMainSync(() -> { 683 mWindowMagnificationAnimationController.moveWindowMagnifierToPosition( 684 targetCenterX, targetCenterY, mAnimationCallback2); 685 advanceTimeBy(mWaitAnimationDuration); 686 }); 687 688 // The callback in moveWindowMagnifierToPosition will return true 689 verify(mAnimationCallback2).onResult(true); 690 // The callback in enableWindowMagnification will return false 691 verify(mAnimationCallback).onResult(false); 692 verifyFinalSpec(DEFAULT_SCALE, targetCenterX, targetCenterY); 693 } 694 695 @Test moveWindowMagnifierToPositionWithCenterUnchanged_enabling_expectedValuesToDefault()696 public void moveWindowMagnifierToPositionWithCenterUnchanged_enabling_expectedValuesToDefault() 697 throws RemoteException { 698 699 enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration, 700 mAnimationCallback); 701 702 getInstrumentation().runOnMainSync(() -> { 703 mWindowMagnificationAnimationController.moveWindowMagnifierToPosition( 704 Float.NaN, Float.NaN, mAnimationCallback2); 705 advanceTimeBy(mWaitAnimationDuration); 706 }); 707 708 // The callback in moveWindowMagnifierToPosition will return true 709 verify(mAnimationCallback2).onResult(true); 710 // The callback in enableWindowMagnification will return false 711 verify(mAnimationCallback).onResult(false); 712 verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y); 713 } 714 715 @Test enableWindowMagnificationWithSameScale_enabled_doNothingButInvokeCallback()716 public void enableWindowMagnificationWithSameScale_enabled_doNothingButInvokeCallback() 717 throws RemoteException { 718 enableWindowMagnificationWithoutAnimation(); 719 720 enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback); 721 722 verify(mSpyController, never()).updateWindowMagnificationInternal(anyFloat(), anyFloat(), 723 anyFloat()); 724 verify(mAnimationCallback).onResult(true); 725 } 726 727 @Test deleteWindowMagnification_enabled_expectedValuesAndInvokeCallback()728 public void deleteWindowMagnification_enabled_expectedValuesAndInvokeCallback() 729 throws RemoteException { 730 enableWindowMagnificationWithoutAnimation(); 731 732 resetMockObjects(); 733 deleteWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback); 734 735 verify(mSpyController, atLeast(2)).updateWindowMagnificationInternal( 736 mScaleCaptor.capture(), 737 mCenterXCaptor.capture(), mCenterYCaptor.capture(), 738 mOffsetXCaptor.capture(), mOffsetYCaptor.capture()); 739 verifyStartValue(mScaleCaptor, DEFAULT_SCALE); 740 verifyStartValue(mCenterXCaptor, Float.NaN); 741 verifyStartValue(mCenterYCaptor, Float.NaN); 742 verifyStartValue(mOffsetXCaptor, 0f); 743 verifyStartValue(mOffsetYCaptor, 0f); 744 verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); 745 verify(mAnimationCallback).onResult(true); 746 } 747 748 @Test deleteWindowMagnificationWithoutCallback_enabled_expectedValues()749 public void deleteWindowMagnificationWithoutCallback_enabled_expectedValues() { 750 enableWindowMagnificationWithoutAnimation(); 751 752 deleteWindowMagnificationAndWaitAnimating(0, null); 753 754 verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); 755 } 756 757 @Test deleteWindowMagnification_disabled_doNothingAndInvokeCallback()758 public void deleteWindowMagnification_disabled_doNothingAndInvokeCallback() 759 throws RemoteException { 760 deleteWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback); 761 762 Mockito.verifyNoMoreInteractions(mSpyController); 763 verify(mAnimationCallback).onResult(true); 764 } 765 766 @Test deleteWindowMagnification_enabling_expectedValuesAndInvokeCallback()767 public void deleteWindowMagnification_enabling_expectedValuesAndInvokeCallback() 768 throws RemoteException { 769 enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration, 770 mAnimationCallback); 771 772 resetMockObjects(); 773 getInstrumentation().runOnMainSync(() -> { 774 mWindowMagnificationAnimationController.deleteWindowMagnification( 775 mAnimationCallback2); 776 mCurrentScale.set(mController.getScale()); 777 mCurrentCenterX.set(mController.getCenterX()); 778 mCurrentCenterY.set(mController.getCenterY()); 779 // ValueAnimator.reverse() could not work correctly with the AnimatorTestRule since it 780 // is using SystemClock in reverse() (b/305731398). Therefore, we call end() on the 781 // animator directly to verify the result of animation is correct instead of querying 782 // the animation frame at a specific timing. 783 mValueAnimator.end(); 784 }); 785 786 // wait for animation returns 787 waitForIdleSync(); 788 789 // Verify the method is called in 790 // {@link ValueAnimator.AnimatorUpdateListener#onAnimationUpdate} once 791 verify(mSpyController).updateWindowMagnificationInternal( 792 mScaleCaptor.capture(), 793 mCenterXCaptor.capture(), mCenterYCaptor.capture(), 794 mOffsetXCaptor.capture(), mOffsetYCaptor.capture()); 795 796 // The animation is playing backwards, so we only check the animated values should not be 797 // greater than the current one. (Asserting the first captured scale) 798 assertTrue(mScaleCaptor.getAllValues().get(0) <= mCurrentScale.get()); 799 // The last captured scale is 1.0 when we delete window magnification. 800 assertEquals(1.0f, mScaleCaptor.getValue(), 0f); 801 verifyStartValue(mCenterXCaptor, Float.NaN); 802 verifyStartValue(mCenterYCaptor, Float.NaN); 803 verifyStartValue(mOffsetXCaptor, 0f); 804 verifyStartValue(mOffsetYCaptor, 0f); 805 verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); 806 verify(mAnimationCallback).onResult(false); 807 verify(mAnimationCallback2).onResult(true); 808 } 809 810 @Test deleteWindowMagnificationWithoutCallback_enabling_expectedValuesAndInvokeCallback()811 public void deleteWindowMagnificationWithoutCallback_enabling_expectedValuesAndInvokeCallback() 812 throws RemoteException { 813 enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration, 814 mAnimationCallback); 815 816 Mockito.reset(mSpyController); 817 deleteWindowMagnificationWithoutAnimation(); 818 819 verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); 820 verify(mAnimationCallback).onResult(false); 821 } 822 823 @Test deleteWindowMagnification_disabling_checkStartAndValues()824 public void deleteWindowMagnification_disabling_checkStartAndValues() throws RemoteException { 825 enableWindowMagnificationWithoutAnimation(); 826 deleteWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration, 827 mAnimationCallback); 828 829 resetMockObjects(); 830 deleteWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback2); 831 832 // Verify the method is called in 833 // {@link ValueAnimator.AnimatorUpdateListener#onAnimationUpdate} once 834 verify(mSpyController).updateWindowMagnificationInternal( 835 mScaleCaptor.capture(), 836 mCenterXCaptor.capture(), mCenterYCaptor.capture(), 837 mOffsetXCaptor.capture(), mOffsetYCaptor.capture()); 838 // The last captured scale is 1.0 when we delete window magnification. 839 assertEquals(1.0f, mScaleCaptor.getValue(), 0f); 840 verifyStartValue(mOffsetXCaptor, 0f); 841 verifyStartValue(mOffsetYCaptor, 0f); 842 verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); 843 verify(mAnimationCallback).onResult(false); 844 verify(mAnimationCallback2).onResult(true); 845 } 846 847 @Test deleteWindowMagnificationWithoutCallback_disabling_checkStartAndValues()848 public void deleteWindowMagnificationWithoutCallback_disabling_checkStartAndValues() 849 throws RemoteException { 850 enableWindowMagnificationWithoutAnimation(); 851 deleteWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration, 852 mAnimationCallback); 853 854 // Verifying that WindowMagnificationController#deleteWindowMagnification is never called 855 // in previous steps 856 verify(mSpyController, never()).deleteWindowMagnification(); 857 858 deleteWindowMagnificationWithoutAnimation(); 859 860 verify(mSpyController).deleteWindowMagnification(); 861 verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); 862 verify(mAnimationCallback).onResult(false); 863 } 864 865 @Test moveWindowMagnifierWithYXRatioLargerThanBase_enabled_movedOnlyVertically()866 public void moveWindowMagnifierWithYXRatioLargerThanBase_enabled_movedOnlyVertically() { 867 enableWindowMagnificationWithoutAnimation(); 868 869 // should move vertically since offsetY/offsetX > HORIZONTAL_LOCK_BASE 870 final float offsetX = 50.0f; 871 final float offsetY = 872 (float) Math.ceil(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE) 873 + 1.0f; 874 getInstrumentation().runOnMainSync(()-> mController.moveWindowMagnifier(offsetX, offsetY)); 875 876 verify(mSpyController).moveWindowMagnifier(offsetX, offsetY); 877 verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y + offsetY); 878 } 879 880 @Test moveWindowMagnifierWithYXRatioLessThanBase_enabled_movedOnlyHorizontally()881 public void moveWindowMagnifierWithYXRatioLessThanBase_enabled_movedOnlyHorizontally() { 882 enableWindowMagnificationWithoutAnimation(); 883 884 // should move vertically since offsetY/offsetX <= HORIZONTAL_LOCK_BASE 885 final float offsetX = 50.0f; 886 final float offsetY = 887 (float) Math.floor(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE) 888 - 1.0f; 889 getInstrumentation().runOnMainSync(() -> 890 mController.moveWindowMagnifier(offsetX, offsetY)); 891 892 verify(mSpyController).moveWindowMagnifier(offsetX, offsetY); 893 verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + offsetX, DEFAULT_CENTER_Y); 894 } 895 896 @Test moveWindowMagnifier_magnifierEnabledAndDiagonalEnabled_movedDiagonally()897 public void moveWindowMagnifier_magnifierEnabledAndDiagonalEnabled_movedDiagonally() { 898 enableWindowMagnificationWithoutAnimation(); 899 900 final float offsetX = 50.0f; 901 final float offsetY = 902 (float) Math.ceil(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE); 903 // while diagonal scrolling enabled, 904 // should move with both offsetX and offsetY without regrading offsetY/offsetX 905 getInstrumentation().runOnMainSync(() -> { 906 mController.setDiagonalScrolling(true); 907 mController.moveWindowMagnifier(offsetX, offsetY); 908 }); 909 910 verify(mSpyController).moveWindowMagnifier(offsetX, offsetY); 911 verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + offsetX, DEFAULT_CENTER_Y + offsetY); 912 } 913 914 @Test moveWindowMagnifierToPosition_enabled()915 public void moveWindowMagnifierToPosition_enabled() { 916 final float targetCenterX = DEFAULT_CENTER_X + 100; 917 final float targetCenterY = DEFAULT_CENTER_Y + 100; 918 enableWindowMagnificationWithoutAnimation(); 919 920 getInstrumentation().runOnMainSync(() -> { 921 mController.moveWindowMagnifierToPosition(targetCenterX, targetCenterY, 922 mAnimationCallback); 923 advanceTimeBy(mWaitAnimationDuration); 924 }); 925 926 verifyFinalSpec(DEFAULT_SCALE, targetCenterX, targetCenterY); 927 } 928 advanceTimeBy(long timeDelta)929 private void advanceTimeBy(long timeDelta) { 930 mAnimatorTestRule.advanceTimeBy(timeDelta); 931 } 932 verifyFinalSpec(float expectedScale, float expectedCenterX, float expectedCenterY)933 private void verifyFinalSpec(float expectedScale, float expectedCenterX, 934 float expectedCenterY) { 935 assertEquals(expectedScale, mController.getScale(), 0f); 936 assertEquals(expectedCenterX, mController.getCenterX(), 0f); 937 assertEquals(expectedCenterY, mController.getCenterY(), 0f); 938 } 939 enableWindowMagnificationWithoutAnimation()940 private void enableWindowMagnificationWithoutAnimation() { 941 enableWindowMagnificationWithoutAnimation( 942 DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y); 943 } 944 enableWindowMagnificationWithoutAnimation( float targetScale, float targetCenterX, float targetCenterY)945 private void enableWindowMagnificationWithoutAnimation( 946 float targetScale, float targetCenterX, float targetCenterY) { 947 getInstrumentation().runOnMainSync(() -> { 948 mWindowMagnificationAnimationController.enableWindowMagnification( 949 targetScale, targetCenterX, targetCenterY, null); 950 }); 951 // wait for animation returns 952 waitForIdleSync(); 953 } 954 enableWindowMagnificationAndWaitAnimating(long duration, @Nullable IRemoteMagnificationAnimationCallback callback)955 private void enableWindowMagnificationAndWaitAnimating(long duration, 956 @Nullable IRemoteMagnificationAnimationCallback callback) { 957 enableWindowMagnificationAndWaitAnimating( 958 duration, DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y, callback); 959 } 960 enableWindowMagnificationAndWaitAnimating( long duration, float targetScale, float targetCenterX, float targetCenterY, @Nullable IRemoteMagnificationAnimationCallback callback)961 private void enableWindowMagnificationAndWaitAnimating( 962 long duration, 963 float targetScale, 964 float targetCenterX, 965 float targetCenterY, 966 @Nullable IRemoteMagnificationAnimationCallback callback) { 967 getInstrumentation().runOnMainSync(() -> { 968 mWindowMagnificationAnimationController.enableWindowMagnification( 969 targetScale, targetCenterX, targetCenterY, callback); 970 advanceTimeBy(duration); 971 }); 972 // wait for animation returns 973 waitForIdleSync(); 974 } 975 deleteWindowMagnificationWithoutAnimation()976 private void deleteWindowMagnificationWithoutAnimation() { 977 getInstrumentation().runOnMainSync(() -> { 978 mWindowMagnificationAnimationController.deleteWindowMagnification(null); 979 }); 980 // wait for animation returns 981 waitForIdleSync(); 982 } 983 deleteWindowMagnificationAndWaitAnimating(long duration, @Nullable IRemoteMagnificationAnimationCallback callback)984 private void deleteWindowMagnificationAndWaitAnimating(long duration, 985 @Nullable IRemoteMagnificationAnimationCallback callback) { 986 getInstrumentation().runOnMainSync(() -> { 987 mWindowMagnificationAnimationController.deleteWindowMagnification(callback); 988 advanceTimeBy(duration); 989 }); 990 // wait for animation returns 991 waitForIdleSync(); 992 } 993 verifyStartValue(ArgumentCaptor<Float> captor, float startValue)994 private void verifyStartValue(ArgumentCaptor<Float> captor, float startValue) { 995 assertEquals(startValue, captor.getAllValues().get(0), 0f); 996 } 997 resetMockObjects()998 private void resetMockObjects() { 999 Mockito.reset(mSpyController); 1000 } 1001 1002 /** 1003 * It observes the methods in {@link WindowMagnificationController} since we couldn't spy it 1004 * directly. 1005 */ 1006 private static class SpyWindowMagnificationController extends WindowMagnificationController { 1007 private WindowMagnificationController mSpyController; 1008 SpyWindowMagnificationController(Context context, Handler handler, WindowMagnificationAnimationController animationController, MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction, WindowMagnifierCallback callback, SysUiState sysUiState, SecureSettings secureSettings, Supplier<SurfaceControlViewHost> scvhSupplier, SfVsyncFrameCallbackProvider sfVsyncFrameProvider)1009 SpyWindowMagnificationController(Context context, 1010 Handler handler, 1011 WindowMagnificationAnimationController animationController, 1012 MirrorWindowControl mirrorWindowControl, 1013 SurfaceControl.Transaction transaction, 1014 WindowMagnifierCallback callback, 1015 SysUiState sysUiState, 1016 SecureSettings secureSettings, 1017 Supplier<SurfaceControlViewHost> scvhSupplier, 1018 SfVsyncFrameCallbackProvider sfVsyncFrameProvider) { 1019 super( 1020 context, 1021 handler, 1022 animationController, 1023 mirrorWindowControl, 1024 transaction, 1025 callback, 1026 sysUiState, 1027 secureSettings, 1028 scvhSupplier, 1029 sfVsyncFrameProvider, 1030 WindowManagerGlobal::getWindowSession); 1031 mSpyController = Mockito.mock(WindowMagnificationController.class); 1032 } 1033 getSpyController()1034 WindowMagnificationController getSpyController() { 1035 return mSpyController; 1036 } 1037 1038 @Override updateWindowMagnificationInternal(float scale, float centerX, float centerY)1039 void updateWindowMagnificationInternal(float scale, float centerX, float centerY) { 1040 super.updateWindowMagnificationInternal(scale, centerX, centerY); 1041 mSpyController.updateWindowMagnificationInternal(scale, centerX, centerY); 1042 } 1043 1044 @Override updateWindowMagnificationInternal(float scale, float centerX, float centerY, float magnificationOffsetFrameRatioX, float magnificationOffsetFrameRatioY)1045 void updateWindowMagnificationInternal(float scale, float centerX, float centerY, 1046 float magnificationOffsetFrameRatioX, float magnificationOffsetFrameRatioY) { 1047 super.updateWindowMagnificationInternal(scale, centerX, centerY, 1048 magnificationOffsetFrameRatioX, magnificationOffsetFrameRatioY); 1049 mSpyController.updateWindowMagnificationInternal(scale, centerX, centerY, 1050 magnificationOffsetFrameRatioX, magnificationOffsetFrameRatioY); 1051 } 1052 1053 @Override deleteWindowMagnification()1054 void deleteWindowMagnification() { 1055 super.deleteWindowMagnification(); 1056 mSpyController.deleteWindowMagnification(); 1057 } 1058 1059 @Override moveWindowMagnifier(float offsetX, float offsetY)1060 void moveWindowMagnifier(float offsetX, float offsetY) { 1061 super.moveWindowMagnifier(offsetX, offsetY); 1062 mSpyController.moveWindowMagnifier(offsetX, offsetY); 1063 } 1064 1065 @Override moveWindowMagnifierToPosition(float positionX, float positionY, IRemoteMagnificationAnimationCallback callback)1066 void moveWindowMagnifierToPosition(float positionX, float positionY, 1067 IRemoteMagnificationAnimationCallback callback) { 1068 super.moveWindowMagnifierToPosition(positionX, positionY, callback); 1069 mSpyController.moveWindowMagnifierToPosition(positionX, positionY, callback); 1070 } 1071 1072 @Override setScale(float scale)1073 void setScale(float scale) { 1074 super.setScale(scale); 1075 mSpyController.setScale(scale); 1076 } 1077 1078 @Override updateSysUIStateFlag()1079 public void updateSysUIStateFlag() { 1080 super.updateSysUIStateFlag(); 1081 mSpyController.updateSysUIStateFlag(); 1082 } 1083 } 1084 newValueAnimator()1085 private ValueAnimator newValueAnimator() { 1086 final ValueAnimator valueAnimator = new ValueAnimator(); 1087 valueAnimator.setDuration(mWaitAnimationDuration); 1088 valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f)); 1089 valueAnimator.setFloatValues(0.0f, 1.0f); 1090 return valueAnimator; 1091 } 1092 } 1093