Change magnification animation callback (2/2)

We send callback when the animation is canceled/reversed due to
the new quest while animating.

Bug: 161669184
Test: atest com.android.systemui.accessibility
      atest com.android.server.accessibility.magnification
Change-Id: Iecd5e1bcf0ac097d4271ff0d277872b1dab0c63d
This commit is contained in:
ryanlwlin
2020-09-08 12:29:36 +08:00
parent aa9a577c35
commit 6c4ffacb47
12 changed files with 250 additions and 156 deletions

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view.accessibility;
/**
* A callback for magnification animation result.
* @hide
*/
oneway interface IRemoteMagnificationAnimationCallback {
/**
* Called when the animation is finished or interrupted during animating.
*
* @param success {@code true} if animating successfully with given spec or the spec did not
* change. Otherwise {@code false}
*/
void onResult(boolean success);
}

View File

@@ -18,8 +18,8 @@ package android.view.accessibility;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.RemoteCallback;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
/**
* Interface for interaction between {@link AccessibilityManagerService}
@@ -38,10 +38,10 @@ oneway interface IWindowMagnificationConnection {
* or {@link Float#NaN} to leave unchanged.
* @param centerY the screen-relative Y coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
* @param endCallback The callback called when the animation is completed.
* @param callback The callback called when the animation is completed or interrupted.
*/
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
in RemoteCallback endCallback);
in IRemoteMagnificationAnimationCallback callback);
/**
* Sets the scale of the window magnifier on specified display.
@@ -55,9 +55,10 @@ oneway interface IWindowMagnificationConnection {
* Disables window magnification on specified display with animation.
*
* @param displayId The logical display id.
* @param endCallback The callback called when the animation is completed.
* @param callback The callback called when the animation is completed or interrupted.
*/
void disableWindowMagnification(int displayId, in RemoteCallback endCallback);
void disableWindowMagnification(int displayId,
in IRemoteMagnificationAnimationCallback callback);
/**
* Moves the window magnifier on the specified display. It has no effect while animating.

View File

@@ -28,4 +28,4 @@ public interface MagnificationAnimationCallback {
* change. Otherwise {@code false}
*/
void onResult(boolean success);
}
}

View File

@@ -24,11 +24,11 @@ import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.util.Log;
import android.view.SurfaceControl;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.accessibility.IWindowMagnificationConnection;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
@@ -101,10 +101,10 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
@MainThread
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
@Nullable RemoteCallback endCallback) {
@Nullable IRemoteMagnificationAnimationCallback callback) {
//TODO: b/144080869 support multi-display.
mWindowMagnificationAnimationController.enableWindowMagnification(scale, centerX, centerY,
endCallback != null ? () -> endCallback.sendResult(null) : null);
callback);
}
@MainThread
@@ -120,10 +120,10 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
}
@MainThread
void disableWindowMagnification(int displayId, @Nullable RemoteCallback endCallback) {
void disableWindowMagnification(int displayId,
@Nullable IRemoteMagnificationAnimationCallback callback) {
//TODO: b/144080869 support multi-display.
mWindowMagnificationAnimationController.deleteWindowMagnification(
endCallback != null ? () -> endCallback.sendResult(null) : null);
mWindowMagnificationAnimationController.deleteWindowMagnification(callback);
}
@Override
@@ -182,10 +182,10 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
@Override
public void enableWindowMagnification(int displayId, float scale, float centerX,
float centerY, RemoteCallback remoteCallback) {
float centerY, IRemoteMagnificationAnimationCallback callback) {
mHandler.post(
() -> mWindowMagnification.enableWindowMagnification(displayId, scale, centerX,
centerY, remoteCallback));
centerY, callback));
}
@Override
@@ -194,9 +194,10 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
}
@Override
public void disableWindowMagnification(int displayId, RemoteCallback remoteCallback) {
public void disableWindowMagnification(int displayId,
IRemoteMagnificationAnimationCallback callback) {
mHandler.post(() -> mWindowMagnification.disableWindowMagnification(displayId,
remoteCallback));
callback));
}
@Override

View File

@@ -22,7 +22,9 @@ import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.os.RemoteException;
import android.util.Log;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.animation.AccelerateInterpolator;
import com.android.internal.annotations.VisibleForTesting;
@@ -38,7 +40,7 @@ import java.lang.annotation.RetentionPolicy;
class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUpdateListener,
Animator.AnimatorListener {
private static final String TAG = "WindowMagnificationBridge";
private static final String TAG = "WindowMagnificationAnimationController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@Retention(RetentionPolicy.SOURCE)
@@ -61,7 +63,7 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
private final Context mContext;
// Called when the animation is ended successfully without cancelling or mStartSpec and
// mEndSpec are equal.
private Runnable mAnimationEndCallback;
private IRemoteMagnificationAnimationCallback mAnimationCallback;
// The flag to ignore the animation end callback.
private boolean mEndAnimationCanceled = false;
@MagnificationState
@@ -93,14 +95,16 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
* or {@link Float#NaN} to leave unchanged.
* @param centerY The screen-relative Y coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
* @param animationEndCallback Called when the transition is complete or the given arguments
* are as same as current values.
* @param animationCallback Called when the transition is complete, the given arguments
* are as same as current values, or the transition is interrupted
* due to the new transition request.
*
* @see #onAnimationUpdate(ValueAnimator)
*/
void enableWindowMagnification(float scale, float centerX, float centerY,
@Nullable Runnable animationEndCallback) {
mAnimationEndCallback = animationEndCallback;
@Nullable IRemoteMagnificationAnimationCallback animationCallback) {
sendAnimationCallback(false);
mAnimationCallback = animationCallback;
setupEnableAnimationSpecs(scale, centerX, centerY);
if (mEndSpec.equals(mStartSpec)) {
if (mState == STATE_DISABLED) {
@@ -108,7 +112,7 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
} else if (mState == STATE_ENABLING || mState == STATE_DISABLING) {
mValueAnimator.cancel();
}
sendCallbackIfNeeded();
sendAnimationCallback(true);
setState(STATE_ENABLED);
} else {
if (mState == STATE_DISABLING) {
@@ -160,14 +164,17 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
* Wraps {@link WindowMagnificationController#deleteWindowMagnification()}} with transition
* animation. If the window magnification is enabling, it runs the animation in reverse.
*
* @param animationEndCallback Called when the transition is complete or the window
* magnification is disabled already.
* @param animationCallback Called when the transition is complete, the given arguments
* are as same as current values, or the transition is interrupted
* due to the new transition request.
*/
void deleteWindowMagnification(@Nullable Runnable animationEndCallback) {
mAnimationEndCallback = animationEndCallback;
void deleteWindowMagnification(
@Nullable IRemoteMagnificationAnimationCallback animationCallback) {
sendAnimationCallback(false);
mAnimationCallback = animationCallback;
if (mState == STATE_DISABLED || mState == STATE_DISABLING) {
if (mState == STATE_DISABLED) {
sendCallbackIfNeeded();
sendAnimationCallback(true);
}
return;
}
@@ -220,7 +227,7 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
} else {
setState(STATE_ENABLED);
}
sendCallbackIfNeeded();
sendAnimationCallback(true);
}
@Override
@@ -236,10 +243,17 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
public void onAnimationRepeat(Animator animation) {
}
private void sendCallbackIfNeeded() {
if (mAnimationEndCallback != null) {
mAnimationEndCallback.run();
mAnimationEndCallback = null;
private void sendAnimationCallback(boolean success) {
if (mAnimationCallback != null) {
try {
mAnimationCallback.onResult(success);
if (DEBUG) {
Log.d(TAG, "sendAnimationCallback success = " + success);
}
} catch (RemoteException e) {
Log.w(TAG, "sendAnimationCallback failed : " + e);
}
mAnimationCallback = null;
}
}

View File

@@ -23,13 +23,13 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Display;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.accessibility.IWindowMagnificationConnection;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
@@ -41,7 +41,6 @@ import com.android.systemui.statusbar.CommandQueue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -66,8 +65,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
@Mock
private ModeSwitchesController mModeSwitchesController;
@Mock
private RemoteCallback mRemoteCallback;
private ArgumentCaptor<Runnable> mRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
private IRemoteMagnificationAnimationCallback mAnimationCallback;
private IWindowMagnificationConnection mIWindowMagnificationConnection;
private WindowMagnification mWindowMagnification;
@@ -92,22 +90,21 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
@Test
public void enableWindowMagnification_passThrough() throws RemoteException {
mIWindowMagnificationConnection.enableWindowMagnification(TEST_DISPLAY, 3.0f, Float.NaN,
Float.NaN, mRemoteCallback);
Float.NaN, mAnimationCallback);
waitForIdleSync();
verify(mWindowMagnificationAnimationController).enableWindowMagnification(eq(3.0f),
eq(Float.NaN), eq(Float.NaN), mRunnableCaptor.capture());
verifyRunnableWrapsRemoteCallback(mRunnableCaptor.getValue());
eq(Float.NaN), eq(Float.NaN), eq(mAnimationCallback));
}
@Test
public void disableWindowMagnification_deleteWindowMagnification() throws RemoteException {
mIWindowMagnificationConnection.disableWindowMagnification(TEST_DISPLAY, mRemoteCallback);
mIWindowMagnificationConnection.disableWindowMagnification(TEST_DISPLAY,
mAnimationCallback);
waitForIdleSync();
verify(mWindowMagnificationAnimationController).deleteWindowMagnification(
mRunnableCaptor.capture());
verifyRunnableWrapsRemoteCallback(mRunnableCaptor.getValue());
mAnimationCallback);
}
@Test
@@ -143,10 +140,5 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
verify(mModeSwitchesController).removeButton(TEST_DISPLAY);
}
private void verifyRunnableWrapsRemoteCallback(Runnable runnable) {
runnable.run();
verify(mRemoteCallback).sendResult(null);
}
}

View File

@@ -18,6 +18,7 @@ package com.android.systemui.accessibility;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.never;
@@ -28,9 +29,11 @@ import android.annotation.Nullable;
import android.app.Instrumentation;
import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemClock;
import android.testing.AndroidTestingRunner;
import android.view.SurfaceControl;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.animation.AccelerateInterpolator;
import androidx.test.InstrumentationRegistry;
@@ -75,9 +78,9 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
@Mock
WindowMagnifierCallback mWindowMagnifierCallback;
@Mock
Runnable mAnimationEndCallback;
IRemoteMagnificationAnimationCallback mAnimationCallback;
@Mock
Runnable mAnimationEndCallback2;
IRemoteMagnificationAnimationCallback mAnimationCallback2;
private SpyWindowMagnificationController mController;
private WindowMagnificationController mSpyController;
private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
@@ -105,8 +108,9 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
}
@Test
public void enableWindowMagnification_disabled_expectedValuesAndInvokeCallback() {
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationEndCallback);
public void enableWindowMagnification_disabled_expectedValuesAndInvokeCallback()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
verify(mSpyController, atLeast(2)).enableWindowMagnification(
mScaleCaptor.capture(),
@@ -115,28 +119,30 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verifyStartValue(mCenterXCaptor, DEFAULT_CENTER_X);
verifyStartValue(mCenterYCaptor, DEFAULT_CENTER_Y);
verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
verify(mAnimationEndCallback).run();
verify(mAnimationCallback).onResult(true);
}
@Test
public void enableWindowMagnificationWithScaleOne_disabled_NoAnimationAndInvokeCallback() {
public void enableWindowMagnificationWithScaleOne_disabled_NoAnimationAndInvokeCallback()
throws RemoteException {
mInstrumentation.runOnMainSync(
() -> {
mWindowMagnificationAnimationController.enableWindowMagnification(1,
DEFAULT_CENTER_X, DEFAULT_CENTER_Y, mAnimationEndCallback);
DEFAULT_CENTER_X, DEFAULT_CENTER_Y, mAnimationCallback);
});
SystemClock.sleep(mWaitingAnimationPeriod);
verify(mSpyController).enableWindowMagnification(1, DEFAULT_CENTER_X,
DEFAULT_CENTER_Y);
verify(mAnimationEndCallback).run();
verify(mAnimationCallback).onResult(true);
}
@Test
public void enableWindowMagnification_enabling_expectedValuesAndInvokeCallback() {
public void enableWindowMagnification_enabling_expectedValuesAndInvokeCallback()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
mAnimationEndCallback);
mAnimationCallback);
final float targetScale = DEFAULT_SCALE + 1.0f;
final float targetCenterX = DEFAULT_CENTER_X + 100;
final float targetCenterY = DEFAULT_CENTER_Y + 100;
@@ -144,7 +150,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
mInstrumentation.runOnMainSync(() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
targetCenterX, targetCenterY, mAnimationEndCallback2);
targetCenterX, targetCenterY, mAnimationCallback2);
mCurrentScale.set(mController.getScale());
mCurrentCenterX.set(mController.getCenterX());
mCurrentCenterY.set(mController.getCenterY());
@@ -158,33 +164,35 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
verify(mAnimationEndCallback, never()).run();
verify(mAnimationEndCallback2).run();
verify(mAnimationCallback).onResult(false);
verify(mAnimationCallback2).onResult(true);
}
@Test
public void enableWindowMagnificationWithSameSpec_enabling_NoAnimationAndInvokeCallback() {
public void enableWindowMagnificationWithSameSpec_enabling_NoAnimationAndInvokeCallback()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
mAnimationEndCallback);
mAnimationCallback);
mInstrumentation.runOnMainSync(() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
Float.NaN, Float.NaN, mAnimationEndCallback2);
Float.NaN, Float.NaN, mAnimationCallback2);
});
SystemClock.sleep(mWaitingAnimationPeriod);
verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
anyFloat());
verify(mAnimationEndCallback, never()).run();
verify(mAnimationEndCallback2).run();
verify(mAnimationCallback).onResult(false);
verify(mAnimationCallback2).onResult(true);
}
@Test
public void enableWindowMagnification_disabling_expectedValuesAndInvokeCallback() {
public void enableWindowMagnification_disabling_expectedValuesAndInvokeCallback()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
mAnimationEndCallback);
mAnimationCallback);
final float targetScale = DEFAULT_SCALE + 1.0f;
final float targetCenterX = DEFAULT_CENTER_X + 100;
final float targetCenterY = DEFAULT_CENTER_Y + 100;
@@ -193,13 +201,14 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
targetCenterX, targetCenterY, mAnimationEndCallback2);
targetCenterX, targetCenterY, mAnimationCallback2);
mCurrentScale.set(mController.getScale());
mCurrentCenterX.set(mController.getCenterX());
mCurrentCenterY.set(mController.getCenterY());
});
// Current spec shouldn't match given spec.
verify(mAnimationEndCallback2, never()).run();
verify(mAnimationCallback2, never()).onResult(anyBoolean());
verify(mAnimationCallback).onResult(false);
SystemClock.sleep(mWaitingAnimationPeriod);
verify(mSpyController, atLeast(2)).enableWindowMagnification(
@@ -213,34 +222,35 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
assertTrue(mCenterYCaptor.getAllValues().get(0) > mCurrentCenterY.get());
assertEquals(targetCenterY, mCenterYCaptor.getValue(), 0f);
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
verify(mAnimationEndCallback, never()).run();
verify(mAnimationEndCallback2).run();
verify(mAnimationCallback2).onResult(true);
}
@Test
public void enableWindowMagnificationWithSameSpec_disabling_NoAnimationAndInvokeCallback() {
public void enableWindowMagnificationWithSameSpec_disabling_NoAnimationAndInvokeCallback()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
mAnimationEndCallback);
mAnimationCallback);
mInstrumentation.runOnMainSync(() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
Float.NaN, Float.NaN, mAnimationEndCallback2);
Float.NaN, Float.NaN, mAnimationCallback2);
});
SystemClock.sleep(mWaitingAnimationPeriod);
verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
anyFloat());
verify(mSpyController, never()).deleteWindowMagnification();
verify(mAnimationEndCallback, never()).run();
verify(mAnimationEndCallback2).run();
verify(mAnimationCallback).onResult(false);
verify(mAnimationCallback2).onResult(true);
}
@Test
public void enableWindowMagnification_enabled_expectedValuesAndInvokeCallback() {
public void enableWindowMagnification_enabled_expectedValuesAndInvokeCallback()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
mAnimationEndCallback);
mAnimationCallback);
final float targetScale = DEFAULT_SCALE + 1.0f;
final float targetCenterX = DEFAULT_CENTER_X + 100;
final float targetCenterY = DEFAULT_CENTER_Y + 100;
@@ -248,7 +258,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
mInstrumentation.runOnMainSync(() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
targetCenterX, targetCenterY, mAnimationEndCallback2);
targetCenterX, targetCenterY, mAnimationCallback2);
mCurrentScale.set(mController.getScale());
mCurrentCenterX.set(mController.getCenterX());
mCurrentCenterY.set(mController.getCenterY());
@@ -262,19 +272,20 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
verify(mAnimationEndCallback, never()).run();
verify(mAnimationEndCallback2).run();
verify(mAnimationCallback).onResult(false);
verify(mAnimationCallback2).onResult(true);
}
@Test
public void enableWindowMagnificationWithSameScale_enabled_doNothingButInvokeCallback() {
public void enableWindowMagnificationWithSameScale_enabled_doNothingButInvokeCallback()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationEndCallback);
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
anyFloat());
verify(mAnimationEndCallback).run();
verify(mAnimationCallback).onResult(true);
}
@Test
@@ -289,10 +300,11 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
}
@Test
public void deleteWindowMagnification_enabled_expectedValuesAndInvokeCallback() {
public void deleteWindowMagnification_enabled_expectedValuesAndInvokeCallback()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationEndCallback);
deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
mCenterXCaptor.capture(), mCenterYCaptor.capture());
@@ -301,27 +313,29 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verifyStartValue(mCenterXCaptor, Float.NaN);
verifyStartValue(mCenterYCaptor, Float.NaN);
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
verify(mAnimationEndCallback).run();
verify(mAnimationCallback).onResult(true);
}
@Test
public void deleteWindowMagnification_disabled_doNothingAndInvokeCallback() {
deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationEndCallback);
public void deleteWindowMagnification_disabled_doNothingAndInvokeCallback()
throws RemoteException {
deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
Mockito.verifyNoMoreInteractions(mSpyController);
verify(mAnimationEndCallback).run();
verify(mAnimationCallback).onResult(true);
}
@Test
public void deleteWindowMagnification_enabling_expectedValuesAndInvokeCallback() {
public void deleteWindowMagnification_enabling_expectedValuesAndInvokeCallback()
throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
mAnimationEndCallback);
mAnimationCallback);
mInstrumentation.runOnMainSync(
() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.deleteWindowMagnification(
mAnimationEndCallback2);
mAnimationCallback2);
mCurrentScale.set(mController.getScale());
mCurrentCenterX.set(mController.getCenterX());
mCurrentCenterY.set(mController.getCenterY());
@@ -339,25 +353,25 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
verifyStartValue(mCenterXCaptor, Float.NaN);
verifyStartValue(mCenterYCaptor, Float.NaN);
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
verify(mAnimationEndCallback, never()).run();
verify(mAnimationEndCallback2).run();
verify(mAnimationCallback).onResult(false);
verify(mAnimationCallback2).onResult(true);
}
@Test
public void deleteWindowMagnification_disabling_checkStartAndValues() {
public void deleteWindowMagnification_disabling_checkStartAndValues() throws RemoteException {
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
mAnimationEndCallback);
mAnimationCallback);
deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationEndCallback2);
deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback2);
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(mAnimationEndCallback, never()).run();
verify(mAnimationEndCallback2).run();
verify(mAnimationCallback).onResult(false);
verify(mAnimationCallback2).onResult(true);
}
@Test
@@ -386,22 +400,22 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
}
private void enableWindowMagnificationAndWaitAnimating(long duration,
@Nullable Runnable endCallback) {
@Nullable IRemoteMagnificationAnimationCallback callback) {
mInstrumentation.runOnMainSync(
() -> {
Mockito.reset(mSpyController);
mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
DEFAULT_CENTER_X, DEFAULT_CENTER_Y, endCallback);
DEFAULT_CENTER_X, DEFAULT_CENTER_Y, callback);
});
SystemClock.sleep(duration);
}
private void deleteWindowMagnificationAndWaitAnimating(long duration,
@Nullable Runnable endCallback) {
@Nullable IRemoteMagnificationAnimationCallback callback) {
mInstrumentation.runOnMainSync(
() -> {
resetMockObjects();
mWindowMagnificationAnimationController.deleteWindowMagnification(endCallback);
mWindowMagnificationAnimationController.deleteWindowMagnification(callback);
});
SystemClock.sleep(duration);
}

View File

@@ -20,11 +20,12 @@ import static android.os.IBinder.DeathRecipient;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.util.Slog;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.accessibility.IWindowMagnificationConnection;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
import android.view.accessibility.MagnificationAnimationCallback;
/**
* A wrapper of {@link IWindowMagnificationConnection}.
@@ -50,9 +51,10 @@ class WindowMagnificationConnectionWrapper {
}
boolean enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
@Nullable RemoteCallback endCallback) {
@Nullable MagnificationAnimationCallback callback) {
try {
mConnection.enableWindowMagnification(displayId, scale, centerX, centerY, endCallback);
mConnection.enableWindowMagnification(displayId, scale, centerX, centerY,
transformToRemoteCallback(callback));
} catch (RemoteException e) {
if (DBG) {
Slog.e(TAG, "Error calling enableWindowMagnification()", e);
@@ -74,9 +76,10 @@ class WindowMagnificationConnectionWrapper {
return true;
}
boolean disableWindowMagnification(int displayId, @Nullable RemoteCallback endCallback) {
boolean disableWindowMagnification(int displayId,
@Nullable MagnificationAnimationCallback callback) {
try {
mConnection.disableWindowMagnification(displayId, endCallback);
mConnection.disableWindowMagnification(displayId, transformToRemoteCallback(callback));
} catch (RemoteException e) {
if (DBG) {
Slog.e(TAG, "Error calling disableWindowMagnification()", e);
@@ -134,4 +137,27 @@ class WindowMagnificationConnectionWrapper {
return true;
}
private static @Nullable
IRemoteMagnificationAnimationCallback transformToRemoteCallback(
MagnificationAnimationCallback callback) {
if (callback == null) {
return null;
}
return new RemoteAnimationCallback(callback);
}
private static class RemoteAnimationCallback extends
IRemoteMagnificationAnimationCallback.Stub {
private final MagnificationAnimationCallback mCallback;
RemoteAnimationCallback(@NonNull MagnificationAnimationCallback callback) {
mCallback = callback;
}
@Override
public void onResult(boolean success) throws RemoteException {
mCallback.onResult(success);
}
}
}

View File

@@ -24,7 +24,6 @@ import android.content.IntentFilter;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.MathUtils;
@@ -33,6 +32,7 @@ import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.accessibility.IWindowMagnificationConnection;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
import android.view.accessibility.MagnificationAnimationCallback;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -234,17 +234,17 @@ public class WindowMagnificationManager implements
* or {@link Float#NaN} to leave unchanged.
* @param centerY The screen-relative Y coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
* @param endCallback Called when the animation is ended without any interruption or the
* window magnifier is disabled already.
* @param animationCallback Called when the animation result is valid.
*/
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
@Nullable Runnable endCallback) {
@Nullable MagnificationAnimationCallback animationCallback) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
magnifier = createWindowMagnifier(displayId);
}
magnifier.enableWindowMagnificationInternal(scale, centerX, centerY, endCallback);
magnifier.enableWindowMagnificationInternal(scale, centerX, centerY,
animationCallback);
}
}
@@ -263,16 +263,16 @@ public class WindowMagnificationManager implements
*
* @param displayId The logical display id.
* @param clear {@true} Clears the state of window magnification.
* @param endCallback Called when the animation is ended without any interruption or the
* window magnifier is disabled already.
* @param animationCallback Called when the animation result is valid.
*/
void disableWindowMagnification(int displayId, boolean clear, Runnable endCallback) {
void disableWindowMagnification(int displayId, boolean clear,
MagnificationAnimationCallback animationCallback) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
return;
}
magnifier.disableWindowMagnificationInternal(endCallback);
magnifier.disableWindowMagnificationInternal(animationCallback);
if (clear) {
mWindowMagnifiers.delete(displayId);
}
@@ -481,22 +481,23 @@ public class WindowMagnificationManager implements
@GuardedBy("mLock")
void enableWindowMagnificationInternal(float scale, float centerX, float centerY,
@Nullable Runnable endCallback) {
@Nullable MagnificationAnimationCallback animationCallback) {
if (mEnabled) {
return;
}
final float normScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
if (mWindowMagnificationManager.enableWindowMagnificationInternal(mDisplayId, normScale,
centerX, centerY, endCallback)) {
centerX, centerY, animationCallback)) {
mScale = normScale;
mEnabled = true;
}
}
@GuardedBy("mLock")
void disableWindowMagnificationInternal(@Nullable Runnable endCallback) {
void disableWindowMagnificationInternal(
@Nullable MagnificationAnimationCallback animationResultCallback) {
if (mEnabled && mWindowMagnificationManager.disableWindowMagnificationInternal(
mDisplayId, endCallback)) {
mDisplayId, animationResultCallback)) {
mEnabled = false;
}
}
@@ -558,20 +559,19 @@ public class WindowMagnificationManager implements
}
private boolean enableWindowMagnificationInternal(int displayId, float scale, float centerX,
float centerY, Runnable endCallback) {
float centerY, MagnificationAnimationCallback animationCallback) {
return mConnectionWrapper != null && mConnectionWrapper.enableWindowMagnification(
displayId, scale, centerX, centerY,
endCallback != null ? new RemoteCallback(bundle -> endCallback.run()) : null);
displayId, scale, centerX, centerY, animationCallback);
}
private boolean setScaleInternal(int displayId, float scale) {
return mConnectionWrapper != null && mConnectionWrapper.setScale(displayId, scale);
}
private boolean disableWindowMagnificationInternal(int displayId, Runnable endCallback) {
private boolean disableWindowMagnificationInternal(int displayId,
MagnificationAnimationCallback animationCallback) {
return mConnectionWrapper != null && mConnectionWrapper.disableWindowMagnification(
displayId,
endCallback != null ? new RemoteCallback(bundle -> endCallback.run()) : null);
displayId, animationCallback);
}
private boolean moveWindowMagnifierInternal(int displayId, float offsetX, float offsetY) {

View File

@@ -28,9 +28,9 @@ import static org.mockito.Mockito.when;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.view.Display;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.accessibility.IWindowMagnificationConnection;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
@@ -38,7 +38,7 @@ import android.view.accessibility.IWindowMagnificationConnectionCallback;
* Mocks the basic logic of window magnification in System UI. We assume the screen size is
* unlimited, so source bounds is always on the center of the mirror window bounds.
*/
class MockWindowMagnificationConnection {
class MockWindowMagnificationConnection {
public static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
private final IWindowMagnificationConnection mConnection;
@@ -72,27 +72,30 @@ class MockWindowMagnificationConnection {
throw new IllegalArgumentException("only support default display :" + displayId);
}
computeMirrorWindowFrame(invocation.getArgument(2), invocation.getArgument(3));
final RemoteCallback callback = invocation.getArgument(4);
final IRemoteMagnificationAnimationCallback callback = invocation.getArgument(4);
if (callback != null) {
callback.sendResult(null);
callback.onResult(true);
}
if (mIMirrorWindowCallback != null) {
mIMirrorWindowCallback.onWindowMagnifierBoundsChanged(TEST_DISPLAY,
mMirrorWindowFrame);
}
mIMirrorWindowCallback.onWindowMagnifierBoundsChanged(TEST_DISPLAY,
mMirrorWindowFrame);
return null;
}).when(mConnection).enableWindowMagnification(anyInt(),
anyFloat(), anyFloat(), anyFloat(), nullable(RemoteCallback.class));
}).when(mConnection).enableWindowMagnification(anyInt(), anyFloat(), anyFloat(), anyFloat(),
nullable(IRemoteMagnificationAnimationCallback.class));
doAnswer((invocation) -> {
final int displayId = invocation.getArgument(0);
if (displayId != TEST_DISPLAY) {
throw new IllegalArgumentException("only support default display :" + displayId);
}
final RemoteCallback callback = invocation.getArgument(1);
final IRemoteMagnificationAnimationCallback callback = invocation.getArgument(1);
if (callback != null) {
callback.sendResult(null);
callback.onResult(true);
}
return null;
}).when(mConnection).disableWindowMagnification(anyInt(), nullable(RemoteCallback.class));
}).when(mConnection).disableWindowMagnification(anyInt(),
nullable(IRemoteMagnificationAnimationCallback.class));
}
private void computeMirrorWindowFrame(float centerX, float centerY) {

View File

@@ -17,14 +17,17 @@
package com.android.server.accessibility.magnification;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.provider.Settings;
import android.view.Display;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.accessibility.IWindowMagnificationConnection;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
import android.view.accessibility.MagnificationAnimationCallback;
import org.junit.Before;
import org.junit.Test;
@@ -40,26 +43,29 @@ public class WindowMagnificationConnectionWrapperTest {
private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
@Mock
private IWindowMagnificationConnection mConnection;
@Mock
private IWindowMagnificationConnectionCallback mCallback;
@Mock
private RemoteCallback.OnResultListener mOnResultListener;
private RemoteCallback mRemoteCallback;
private MagnificationAnimationCallback mAnimationCallback;
private MockWindowMagnificationConnection mMockWindowMagnificationConnection;
private WindowMagnificationConnectionWrapper mConnectionWrapper;
@Before
public void setUp() {
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
mMockWindowMagnificationConnection = new MockWindowMagnificationConnection();
mConnection = mMockWindowMagnificationConnection.getConnection();
mConnectionWrapper = new WindowMagnificationConnectionWrapper(mConnection);
mRemoteCallback = new RemoteCallback(mOnResultListener);
}
@Test
public void enableWindowMagnification() throws RemoteException {
mConnectionWrapper.enableWindowMagnification(TEST_DISPLAY, 2, 100f, 200f, mRemoteCallback);
verify(mConnection).enableWindowMagnification(TEST_DISPLAY, 2, 100f, 200f, mRemoteCallback);
mConnectionWrapper.enableWindowMagnification(TEST_DISPLAY, 2, 100f, 200f,
mAnimationCallback);
verify(mAnimationCallback).onResult(true);
}
@Test
@@ -70,8 +76,11 @@ public class WindowMagnificationConnectionWrapperTest {
@Test
public void disableWindowMagnification() throws RemoteException {
mConnectionWrapper.disableWindowMagnification(TEST_DISPLAY, mRemoteCallback);
verify(mConnection).disableWindowMagnification(TEST_DISPLAY, mRemoteCallback);
mConnectionWrapper.disableWindowMagnification(TEST_DISPLAY, mAnimationCallback);
verify(mConnection).disableWindowMagnification(eq(TEST_DISPLAY),
any(IRemoteMagnificationAnimationCallback.class));
verify(mAnimationCallback).onResult(true);
}
@Test
@@ -99,5 +108,4 @@ public class WindowMagnificationConnectionWrapperTest {
mConnectionWrapper.setConnectionCallback(mCallback);
verify(mConnection).setConnectionCallback(mCallback);
}
}

View File

@@ -48,6 +48,7 @@ import android.view.Display;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
import android.view.accessibility.MagnificationAnimationCallback;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
@@ -73,7 +74,7 @@ public class WindowMagnificationManagerTest {
@Mock
private StatusBarManagerInternal mMockStatusBarManagerInternal;
@Mock
private Runnable mEndCallback;
private MagnificationAnimationCallback mAnimationCallback;
private MockContentResolver mResolver;
private WindowMagnificationManager mWindowMagnificationManager;
@@ -177,9 +178,9 @@ public class WindowMagnificationManagerTest {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, 200f, 300f,
mEndCallback);
mAnimationCallback);
verify(mEndCallback).run();
verify(mAnimationCallback).onResult(true);
}
@Test
@@ -198,9 +199,10 @@ public class WindowMagnificationManagerTest {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false, mEndCallback);
mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false,
mAnimationCallback);
verify(mEndCallback).run();
verify(mAnimationCallback).onResult(true);
}
@Test