Merge "Support enable window magnification without animation"

This commit is contained in:
Ryan Lin
2021-11-12 06:17:09 +00:00
committed by Android (Google) Code Review
8 changed files with 214 additions and 27 deletions

View File

@@ -21,6 +21,9 @@ package android.view.accessibility;
* @hide
*/
public interface MagnificationAnimationCallback {
MagnificationAnimationCallback STUB_ANIMATION_CALLBACK = success -> {
};
/**
* Called when the animation is finished or interrupted during animating.
*

View File

@@ -106,6 +106,15 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
void enableWindowMagnification(float scale, float centerX, float centerY,
@Nullable IRemoteMagnificationAnimationCallback animationCallback) {
sendAnimationCallback(false);
// Enable window magnification without animation immediately.
if (animationCallback == null) {
if (mState == STATE_ENABLING || mState == STATE_DISABLING) {
mValueAnimator.cancel();
}
mController.enableWindowMagnification(scale, centerX, centerY);
setState(STATE_ENABLED);
return;
}
mAnimationCallback = animationCallback;
setupEnableAnimationSpecs(scale, centerX, centerY);
if (mEndSpec.equals(mStartSpec)) {
@@ -173,6 +182,16 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
void deleteWindowMagnification(
@Nullable IRemoteMagnificationAnimationCallback animationCallback) {
sendAnimationCallback(false);
// Delete window magnification without animation.
if (animationCallback == null) {
if (mState == STATE_ENABLING || mState == STATE_DISABLING) {
mValueAnimator.cancel();
}
mController.deleteWindowMagnification();
setState(STATE_DISABLED);
return;
}
mAnimationCallback = animationCallback;
if (mState == STATE_DISABLED || mState == STATE_DISABLING) {
if (mState == STATE_DISABLED) {
@@ -223,8 +242,7 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
if (mEndAnimationCanceled) {
return;
}
if (isReverse) {
mController.deleteWindowMagnification();
if (Float.isNaN(mController.getScale())) {
setState(STATE_DISABLED);
} else {
setState(STATE_ENABLED);

View File

@@ -262,6 +262,9 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
* Deletes the magnification window.
*/
void deleteWindowMagnification() {
if (!isWindowVisible()) {
return;
}
if (mMirrorSurface != null) {
mTransaction.remove(mMirrorSurface).apply();
mMirrorSurface = null;
@@ -690,7 +693,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
}
/**
* Enables window magnification with specified parameters.
* Enables window magnification with specified parameters. If the given scale is <strong>less
* than or equal to 1.0f<strong>, then
* {@link WindowMagnificationController#deleteWindowMagnification()} will be called instead to
* be consistent with the behavior of display magnification.
*
* @param scale the target scale, or {@link Float#NaN} to leave unchanged
* @param centerX the screen-relative X coordinate around which to center,
@@ -699,6 +705,11 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
* or {@link Float#NaN} to leave unchanged.
*/
void enableWindowMagnification(float scale, float centerX, float centerY) {
if (Float.compare(scale, 1.0f) <= 0) {
deleteWindowMagnification();
return;
}
final float offsetX = Float.isNaN(centerX) ? 0
: centerX - mMagnificationFrame.exactCenterX();
final float offsetY = Float.isNaN(centerY) ? 0

View File

@@ -48,6 +48,7 @@ import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
@@ -61,11 +62,11 @@ import java.util.concurrent.atomic.AtomicReference;
@RunWith(AndroidTestingRunner.class)
public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
private static final float DEFAULT_SCALE = 3.0f;
private static final float DEFAULT_SCALE = 4.0f;
private static final float DEFAULT_CENTER_X = 400.0f;
private static final float DEFAULT_CENTER_Y = 500.0f;
// The duration couldn't too short, otherwise the ValueAnimator won't work in expectation.
private static final long ANIMATION_DURATION_MS = 200;
private static final long ANIMATION_DURATION_MS = 300;
private AtomicReference<Float> mCurrentScale = new AtomicReference<>((float) 0);
private AtomicReference<Float> mCurrentCenterX = new AtomicReference<>((float) 0);
@@ -84,7 +85,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
IRemoteMagnificationAnimationCallback mAnimationCallback;
@Mock
IRemoteMagnificationAnimationCallback mAnimationCallback2;
@Mock
@Mock(answer = Answers.RETURNS_SELF)
SysUiState mSysUiState;
private SpyWindowMagnificationController mController;
private WindowMagnificationController mSpyController;
@@ -127,6 +128,28 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verify(mAnimationCallback).onResult(true);
}
@Test
public void enableWindowMagnificationWithoutCallback_disabled_expectedValues() {
enableWindowMagnificationWithoutAnimation();
verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
}
@Test
public void enableWindowMagnificationWithoutCallback_enabled_expectedValues() {
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
final float targetScale = DEFAULT_SCALE + 1.0f;
final float targetCenterX = DEFAULT_CENTER_X + 100;
final float targetCenterY = DEFAULT_CENTER_Y + 100;
mInstrumentation.runOnMainSync(
() -> {
mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
targetCenterX, targetCenterY, null);
});
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
}
@Test
public void enableWindowMagnificationWithScaleOne_disabled_NoAnimationAndInvokeCallback()
@@ -173,6 +196,52 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verify(mAnimationCallback2).onResult(true);
}
@Test
public void enableWindowMagnificationWithScaleOne_enabled_AnimationAndInvokeCallback()
throws RemoteException {
enableWindowMagnificationWithoutAnimation();
mInstrumentation.runOnMainSync(() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.enableWindowMagnification(1.0f,
DEFAULT_CENTER_X + 100, DEFAULT_CENTER_Y + 100, mAnimationCallback);
mCurrentScale.set(mController.getScale());
mCurrentCenterX.set(mController.getCenterX());
mCurrentCenterY.set(mController.getCenterY());
});
SystemClock.sleep(mWaitingAnimationPeriod);
verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
mCenterXCaptor.capture(), mCenterYCaptor.capture());
verifyStartValue(mScaleCaptor, mCurrentScale.get());
verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
// It presents the window magnification is disabled.
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
verify(mAnimationCallback).onResult(true);
}
@Test
public void
enableMagnificationWithoutCallback_enabling_expectedValuesAndInvokeFormerCallback()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
mAnimationCallback);
final float targetScale = DEFAULT_SCALE - 1.0f;
final float targetCenterX = DEFAULT_CENTER_X + 100;
final float targetCenterY = DEFAULT_CENTER_Y + 100;
mInstrumentation.runOnMainSync(() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
targetCenterX, targetCenterY, null);
});
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
verify(mAnimationCallback).onResult(false);
}
@Test
public void enableWindowMagnificationWithSameSpec_enabling_NoAnimationAndInvokeCallback()
throws RemoteException {
@@ -230,6 +299,28 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verify(mAnimationCallback2).onResult(true);
}
@Test
public void
enableMagnificationWithoutCallback_disabling_expectedValuesAndInvokeFormerCallback()
throws RemoteException {
enableWindowMagnificationWithoutAnimation();
deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
mAnimationCallback);
final float targetScale = DEFAULT_SCALE + 1.0f;
final float targetCenterX = DEFAULT_CENTER_X + 100;
final float targetCenterY = DEFAULT_CENTER_Y + 100;
mInstrumentation.runOnMainSync(
() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
targetCenterX, targetCenterY, null);
});
verify(mAnimationCallback).onResult(false);
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
}
@Test
public void enableWindowMagnificationWithSameSpec_disabling_NoAnimationAndInvokeCallback()
throws RemoteException {
@@ -254,8 +345,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
@Test
public void enableWindowMagnification_enabled_expectedValuesAndInvokeCallback()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
mAnimationCallback);
enableWindowMagnificationWithoutAnimation();
final float targetScale = DEFAULT_SCALE + 1.0f;
final float targetCenterX = DEFAULT_CENTER_X + 100;
final float targetCenterY = DEFAULT_CENTER_Y + 100;
@@ -277,7 +367,6 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
verify(mAnimationCallback).onResult(false);
verify(mAnimationCallback2).onResult(true);
}
@@ -295,7 +384,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
@Test
public void setScale_enabled_expectedScale() {
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
enableWindowMagnificationWithoutAnimation();
mInstrumentation.runOnMainSync(
() -> mWindowMagnificationAnimationController.setScale(DEFAULT_SCALE + 1));
@@ -307,13 +396,12 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
@Test
public void deleteWindowMagnification_enabled_expectedValuesAndInvokeCallback()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
enableWindowMagnificationWithoutAnimation();
deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
mCenterXCaptor.capture(), mCenterYCaptor.capture());
verify(mSpyController).deleteWindowMagnification();
verifyStartValue(mScaleCaptor, DEFAULT_SCALE);
verifyStartValue(mCenterXCaptor, Float.NaN);
verifyStartValue(mCenterYCaptor, Float.NaN);
@@ -321,6 +409,15 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verify(mAnimationCallback).onResult(true);
}
@Test
public void deleteWindowMagnificationWithoutCallback_enabled_expectedValues() {
enableWindowMagnificationWithoutAnimation();
deleteWindowMagnificationAndWaitAnimating(0, null);
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
}
@Test
public void deleteWindowMagnification_disabled_doNothingAndInvokeCallback()
throws RemoteException {
@@ -346,10 +443,8 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
mCurrentCenterY.set(mController.getCenterY());
});
SystemClock.sleep(mWaitingAnimationPeriod);
verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
mCenterXCaptor.capture(), mCenterYCaptor.capture());
verify(mSpyController).deleteWindowMagnification();
//The animation is in verse, so we only check the start values should no be greater than
// the current one.
@@ -362,6 +457,22 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verify(mAnimationCallback2).onResult(true);
}
@Test
public void deleteWindowMagnificationWithoutCallback_enabling_expectedValuesAndInvokeCallback()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
mAnimationCallback);
mInstrumentation.runOnMainSync(
() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.deleteWindowMagnification(null);
});
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
verify(mAnimationCallback).onResult(false);
}
@Test
public void deleteWindowMagnification_disabling_checkStartAndValues() throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
@@ -372,7 +483,6 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
mCenterXCaptor.capture(), mCenterYCaptor.capture());
verify(mSpyController).deleteWindowMagnification();
assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
verify(mAnimationCallback).onResult(false);
@@ -380,8 +490,22 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
}
@Test
public void moveWindowMagnifier_enabled() {
public void deleteWindowMagnificationWithoutCallback_disabling_checkStartAndValues()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
mAnimationCallback);
deleteWindowMagnificationAndWaitAnimating(0, null);
verify(mSpyController).deleteWindowMagnification();
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
verify(mAnimationCallback).onResult(false);
}
@Test
public void moveWindowMagnifier_enabled() {
enableWindowMagnificationWithoutAnimation();
mInstrumentation.runOnMainSync(
() -> mWindowMagnificationAnimationController.moveWindowMagnifier(100f, 200f));
@@ -411,6 +535,15 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
assertEquals(expectedCenterY, mController.getCenterY(), 0f);
}
private void enableWindowMagnificationWithoutAnimation() {
mInstrumentation.runOnMainSync(
() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
DEFAULT_CENTER_X, DEFAULT_CENTER_Y, null);
});
}
private void enableWindowMagnificationAndWaitAnimating(long duration,
@Nullable IRemoteMagnificationAnimationCallback callback) {
mInstrumentation.runOnMainSync(
@@ -484,12 +617,17 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
mSpyController.setScale(scale);
}
@Override
public void updateSysUIStateFlag() {
super.updateSysUIStateFlag();
mSpyController.updateSysUIStateFlag();
}
@Override
void onConfigurationChanged(int configDiff) {
super.onConfigurationChanged(configDiff);
mSpyController.onConfigurationChanged(configDiff);
}
}
private static ValueAnimator newValueAnimator() {

View File

@@ -468,6 +468,21 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
com.android.internal.R.string.android_system_label), getAccessibilityWindowTitle());
}
@Test
public void enableWindowMagnificationWithScaleLessThanOne_enabled_disabled() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
Float.NaN);
});
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(0.9f, Float.NaN,
Float.NaN);
});
assertEquals(Float.NaN, mWindowMagnificationController.getScale(), 0);
}
@Test
public void onLocaleChanged_enabled_updateA11yWindowTitle() {
final String newA11yWindowTitle = "new a11y window title";

View File

@@ -17,6 +17,7 @@
package com.android.server.accessibility.magnification;
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
import android.animation.Animator;
import android.animation.ValueAnimator;
@@ -66,9 +67,6 @@ public class FullScreenMagnificationController {
private static final boolean DEBUG = false;
private static final String LOG_TAG = "FullScreenMagnificationController";
private static final MagnificationAnimationCallback STUB_ANIMATION_CALLBACK = success -> {
};
private static final boolean DEBUG_SET_MAGNIFICATION_SPEC = false;
private final Object mLock;

View File

@@ -18,6 +18,7 @@ package com.android.server.accessibility.magnification;
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION;
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK;
import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -74,7 +75,7 @@ public class WindowMagnificationManager implements
public void onReceive(Context context, Intent intent) {
final int displayId = context.getDisplayId();
removeMagnificationButton(displayId);
disableWindowMagnification(displayId, false);
disableWindowMagnification(displayId, false, null);
}
};
@@ -272,7 +273,7 @@ public class WindowMagnificationManager implements
* or {@link Float#NaN} to leave unchanged.
*/
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
enableWindowMagnification(displayId, scale, centerX, centerY, null);
enableWindowMagnification(displayId, scale, centerX, centerY, STUB_ANIMATION_CALLBACK);
}
/**
@@ -314,7 +315,7 @@ public class WindowMagnificationManager implements
* @param clear {@true} Clears the state of window magnification.
*/
void disableWindowMagnification(int displayId, boolean clear) {
disableWindowMagnification(displayId, clear, null);
disableWindowMagnification(displayId, clear, STUB_ANIMATION_CALLBACK);
}
/**

View File

@@ -19,6 +19,7 @@ package com.android.server.accessibility.magnification;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -169,13 +170,14 @@ public class WindowMagnificationManagerTest {
}
@Test
public void enable_hasConnection_enableWindowMagnification() throws RemoteException {
public void enableWithAnimation_hasConnection_enableWindowMagnification()
throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, 200f, 300f);
verify(mMockConnection.getConnection()).enableWindowMagnification(TEST_DISPLAY, 2f,
200f, 300f, null);
verify(mMockConnection.getConnection()).enableWindowMagnification(eq(TEST_DISPLAY), eq(2f),
eq(200f), eq(300f), notNull());
}
@Test
@@ -199,7 +201,8 @@ public class WindowMagnificationManagerTest {
mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false);
verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY, null);
verify(mMockConnection.getConnection()).disableWindowMagnification(eq(TEST_DISPLAY),
notNull());
}
@Test