Merge "Change magnification animation callback (1/2)"
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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
|
||||
*/
|
||||
public interface MagnificationAnimationCallback {
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import android.util.SparseArray;
|
||||
import android.view.Display;
|
||||
import android.view.MagnificationSpec;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.MagnificationAnimationCallback;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
|
||||
import com.android.internal.R;
|
||||
@@ -63,7 +64,7 @@ public class FullScreenMagnificationController {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String LOG_TAG = "FullScreenMagnificationController";
|
||||
|
||||
private static final Runnable STUB_RUNNABLE = () -> {
|
||||
private static final MagnificationAnimationCallback STUB_ANIMATION_CALLBACK = success -> {
|
||||
};
|
||||
public static final float MIN_SCALE = 1.0f;
|
||||
public static final float MAX_SCALE = 8.0f;
|
||||
@@ -304,18 +305,19 @@ public class FullScreenMagnificationController {
|
||||
}
|
||||
}
|
||||
|
||||
void sendSpecToAnimation(MagnificationSpec spec, Runnable endCallback) {
|
||||
void sendSpecToAnimation(MagnificationSpec spec,
|
||||
MagnificationAnimationCallback animationCallback) {
|
||||
if (DEBUG) {
|
||||
Slog.i(LOG_TAG,
|
||||
"sendSpecToAnimation(spec = " + spec + ", endCallback = " + endCallback
|
||||
+ ")");
|
||||
"sendSpecToAnimation(spec = " + spec + ", animationCallback = "
|
||||
+ animationCallback + ")");
|
||||
}
|
||||
if (Thread.currentThread().getId() == mMainThreadId) {
|
||||
mSpecAnimationBridge.updateSentSpecMainThread(spec, endCallback);
|
||||
mSpecAnimationBridge.updateSentSpecMainThread(spec, animationCallback);
|
||||
} else {
|
||||
final Message m = PooledLambda.obtainMessage(
|
||||
SpecAnimationBridge::updateSentSpecMainThread,
|
||||
mSpecAnimationBridge, spec, endCallback);
|
||||
mSpecAnimationBridge, spec, animationCallback);
|
||||
mControllerCtx.getHandler().sendMessage(m);
|
||||
}
|
||||
}
|
||||
@@ -415,11 +417,11 @@ public class FullScreenMagnificationController {
|
||||
|
||||
@GuardedBy("mLock")
|
||||
boolean reset(boolean animate) {
|
||||
return reset(transformToStubRunnable(animate));
|
||||
return reset(transformToStubCallback(animate));
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
boolean reset(Runnable endCallback) {
|
||||
boolean reset(MagnificationAnimationCallback animationCallback) {
|
||||
if (!mRegistered) {
|
||||
return false;
|
||||
}
|
||||
@@ -430,7 +432,7 @@ public class FullScreenMagnificationController {
|
||||
onMagnificationChangedLocked();
|
||||
}
|
||||
mIdOfLastServiceToMagnify = INVALID_ID;
|
||||
sendSpecToAnimation(spec, endCallback);
|
||||
sendSpecToAnimation(spec, animationCallback);
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -458,24 +460,23 @@ public class FullScreenMagnificationController {
|
||||
final float centerX = normPivotX + offsetX;
|
||||
final float centerY = normPivotY + offsetY;
|
||||
mIdOfLastServiceToMagnify = id;
|
||||
return setScaleAndCenter(scale, centerX, centerY, transformToStubRunnable(animate), id);
|
||||
return setScaleAndCenter(scale, centerX, centerY, transformToStubCallback(animate), id);
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
boolean setScaleAndCenter(float scale, float centerX, float centerY,
|
||||
Runnable endCallback, int id) {
|
||||
MagnificationAnimationCallback animationCallback, int id) {
|
||||
if (!mRegistered) {
|
||||
return false;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Slog.i(LOG_TAG,
|
||||
"setScaleAndCenterLocked(scale = " + scale + ", centerX = " + centerX
|
||||
+ ", centerY = " + centerY + ", endCallback = " + endCallback
|
||||
+ ", id = " + id
|
||||
+ ")");
|
||||
+ ", centerY = " + centerY + ", endCallback = "
|
||||
+ animationCallback + ", id = " + id + ")");
|
||||
}
|
||||
final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
|
||||
sendSpecToAnimation(mCurrentMagnificationSpec, endCallback);
|
||||
sendSpecToAnimation(mCurrentMagnificationSpec, animationCallback);
|
||||
if (isMagnifying() && (id != INVALID_ID)) {
|
||||
mIdOfLastServiceToMagnify = id;
|
||||
}
|
||||
@@ -875,7 +876,7 @@ public class FullScreenMagnificationController {
|
||||
* the spec did not change
|
||||
*/
|
||||
public boolean reset(int displayId, boolean animate) {
|
||||
return reset(displayId, animate ? STUB_RUNNABLE : null);
|
||||
return reset(displayId, animate ? STUB_ANIMATION_CALLBACK : null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -883,18 +884,19 @@ public class FullScreenMagnificationController {
|
||||
* transition.
|
||||
*
|
||||
* @param displayId The logical display id.
|
||||
* @param endCallback Called when the animation is ended or the spec did not change.
|
||||
* @param animationCallback Called when the animation result is valid.
|
||||
* {@code null} to transition immediately
|
||||
* @return {@code true} if the magnification spec changed, {@code false} if
|
||||
* the spec did not change
|
||||
*/
|
||||
public boolean reset(int displayId, Runnable endCallback) {
|
||||
public boolean reset(int displayId,
|
||||
MagnificationAnimationCallback animationCallback) {
|
||||
synchronized (mLock) {
|
||||
final DisplayMagnification display = mDisplays.get(displayId);
|
||||
if (display == null) {
|
||||
return false;
|
||||
}
|
||||
return display.reset(endCallback);
|
||||
return display.reset(animationCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -946,7 +948,7 @@ public class FullScreenMagnificationController {
|
||||
return false;
|
||||
}
|
||||
return display.setScaleAndCenter(Float.NaN, centerX, centerY,
|
||||
animate ? STUB_RUNNABLE : null, id);
|
||||
animate ? STUB_ANIMATION_CALLBACK : null, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -970,7 +972,7 @@ public class FullScreenMagnificationController {
|
||||
public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
|
||||
boolean animate, int id) {
|
||||
return setScaleAndCenter(displayId, scale, centerX, centerY,
|
||||
transformToStubRunnable(animate), id);
|
||||
transformToStubCallback(animate), id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -984,20 +986,20 @@ public class FullScreenMagnificationController {
|
||||
* center and scale, or {@link Float#NaN} to leave unchanged
|
||||
* @param centerY the screen-relative Y coordinate around which to
|
||||
* center and scale, or {@link Float#NaN} to leave unchanged
|
||||
* @param endCallback called when the transition is finished successfully or the spec did not
|
||||
* change. {@code null} to transition immediately.
|
||||
* @param animationCallback Called when the animation result is valid.
|
||||
* {@code null} to transition immediately
|
||||
* @param id the ID of the service requesting the change
|
||||
* @return {@code true} if the magnification spec changed, {@code false} if
|
||||
* the spec did not change
|
||||
*/
|
||||
public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
|
||||
Runnable endCallback, int id) {
|
||||
MagnificationAnimationCallback animationCallback, int id) {
|
||||
synchronized (mLock) {
|
||||
final DisplayMagnification display = mDisplays.get(displayId);
|
||||
if (display == null) {
|
||||
return false;
|
||||
}
|
||||
return display.setScaleAndCenter(scale, centerX, centerY, endCallback, id);
|
||||
return display.setScaleAndCenter(scale, centerX, centerY, animationCallback, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1230,7 +1232,7 @@ public class FullScreenMagnificationController {
|
||||
private final ValueAnimator mValueAnimator;
|
||||
|
||||
// Called when the callee wants animating and the sent spec matches the target spec.
|
||||
private Runnable mEndCallback;
|
||||
private MagnificationAnimationCallback mAnimationCallback;
|
||||
private final Object mLock;
|
||||
|
||||
private final int mDisplayId;
|
||||
@@ -1268,33 +1270,35 @@ public class FullScreenMagnificationController {
|
||||
}
|
||||
}
|
||||
|
||||
void updateSentSpecMainThread(MagnificationSpec spec, Runnable endCallback) {
|
||||
void updateSentSpecMainThread(MagnificationSpec spec,
|
||||
MagnificationAnimationCallback animationCallback) {
|
||||
if (mValueAnimator.isRunning()) {
|
||||
// Avoid AnimationEnd Callback.
|
||||
mEndCallback = null;
|
||||
mValueAnimator.cancel();
|
||||
}
|
||||
|
||||
mEndCallback = endCallback;
|
||||
mAnimationCallback = animationCallback;
|
||||
// If the current and sent specs don't match, update the sent spec.
|
||||
synchronized (mLock) {
|
||||
final boolean changed = !mSentMagnificationSpec.equals(spec);
|
||||
if (changed) {
|
||||
if (mEndCallback != null) {
|
||||
if (mAnimationCallback != null) {
|
||||
animateMagnificationSpecLocked(spec);
|
||||
} else {
|
||||
setMagnificationSpecLocked(spec);
|
||||
}
|
||||
} else {
|
||||
sendEndCallbackMainThread();
|
||||
sendEndCallbackMainThread(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendEndCallbackMainThread() {
|
||||
if (mEndCallback != null) {
|
||||
mEndCallback.run();
|
||||
mEndCallback = null;
|
||||
private void sendEndCallbackMainThread(boolean success) {
|
||||
if (mAnimationCallback != null) {
|
||||
if (DEBUG) {
|
||||
Slog.d(LOG_TAG, "sendEndCallbackMainThread: " + success);
|
||||
}
|
||||
mAnimationCallback.onResult(success);
|
||||
mAnimationCallback = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1337,17 +1341,16 @@ public class FullScreenMagnificationController {
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
sendEndCallbackMainThread();
|
||||
sendEndCallbackMainThread(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
|
||||
sendEndCallbackMainThread(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1481,7 +1484,7 @@ public class FullScreenMagnificationController {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Runnable transformToStubRunnable(boolean animate) {
|
||||
return animate ? STUB_RUNNABLE : null;
|
||||
private static MagnificationAnimationCallback transformToStubCallback(boolean animate) {
|
||||
return animate ? STUB_ANIMATION_CALLBACK : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.os.Looper;
|
||||
import android.view.MagnificationSpec;
|
||||
import android.view.accessibility.MagnificationAnimationCallback;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
@@ -99,12 +100,12 @@ public class FullScreenMagnificationControllerTest {
|
||||
ValueAnimator.AnimatorListener mStateListener;
|
||||
|
||||
FullScreenMagnificationController mFullScreenMagnificationController;
|
||||
Runnable mEndCallback;
|
||||
MagnificationAnimationCallback mAnimationCallback;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Looper looper = InstrumentationRegistry.getContext().getMainLooper();
|
||||
mEndCallback = Mockito.mock(Runnable.class);
|
||||
mAnimationCallback = Mockito.mock(MagnificationAnimationCallback.class);
|
||||
// Pretending ID of the Thread associated with looper as main thread ID in controller
|
||||
when(mMockContext.getMainLooper()).thenReturn(looper);
|
||||
when(mMockControllerCtx.getContext()).thenReturn(mMockContext);
|
||||
@@ -323,7 +324,6 @@ public class FullScreenMagnificationControllerTest {
|
||||
for (int i = 0; i < DISPLAY_COUNT; i++) {
|
||||
setScaleAndCenter_animated_stateChangesAndAnimationHappens(i);
|
||||
resetMockWindowManager();
|
||||
Mockito.reset(mEndCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ public class FullScreenMagnificationControllerTest {
|
||||
MagnificationSpec endSpec = getMagnificationSpec(scale, offsets);
|
||||
|
||||
assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId, scale,
|
||||
newCenter.x, newCenter.y, mEndCallback, SERVICE_ID_1));
|
||||
newCenter.x, newCenter.y, mAnimationCallback, SERVICE_ID_1));
|
||||
mMessageCapturingHandler.sendAllMessages();
|
||||
|
||||
assertEquals(newCenter.x, mFullScreenMagnificationController.getCenterX(displayId), 0.5);
|
||||
@@ -365,18 +365,17 @@ public class FullScreenMagnificationControllerTest {
|
||||
mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
|
||||
mStateListener.onAnimationEnd(mMockValueAnimator);
|
||||
verify(mMockWindowManager).setMagnificationSpec(eq(displayId), argThat(closeTo(endSpec)));
|
||||
verify(mEndCallback).run();
|
||||
verify(mAnimationCallback).onResult(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetScaleAndCenterWithAnimation_sameSpec_noAnimationButInvokeEndCallback() {
|
||||
for (int i = 0; i < DISPLAY_COUNT; i++) {
|
||||
setScaleAndCenter_sameSpec_noAnimationButInvokeEndCallback(i);
|
||||
Mockito.reset(mEndCallback);
|
||||
setScaleAndCenter_sameSpec_noAnimationButInvokeCallbacks(i);
|
||||
}
|
||||
}
|
||||
|
||||
private void setScaleAndCenter_sameSpec_noAnimationButInvokeEndCallback(int displayId) {
|
||||
private void setScaleAndCenter_sameSpec_noAnimationButInvokeCallbacks(int displayId) {
|
||||
register(displayId);
|
||||
final PointF center = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
|
||||
final float targetScale = 2.0f;
|
||||
@@ -385,11 +384,11 @@ public class FullScreenMagnificationControllerTest {
|
||||
mMessageCapturingHandler.sendAllMessages();
|
||||
|
||||
assertFalse(mFullScreenMagnificationController.setScaleAndCenter(displayId,
|
||||
targetScale, center.x, center.y, mEndCallback, SERVICE_ID_1));
|
||||
targetScale, center.x, center.y, mAnimationCallback, SERVICE_ID_1));
|
||||
mMessageCapturingHandler.sendAllMessages();
|
||||
|
||||
verify(mMockValueAnimator, never()).start();
|
||||
verify(mEndCallback).run();
|
||||
verify(mAnimationCallback).onResult(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -673,38 +672,38 @@ public class FullScreenMagnificationControllerTest {
|
||||
public void testReset_notMagnifying_noStateChangeButInvokeCallback() {
|
||||
for (int i = 0; i < DISPLAY_COUNT; i++) {
|
||||
reset_notMagnifying_noStateChangeButInvokeCallback(i);
|
||||
Mockito.reset(mEndCallback);
|
||||
}
|
||||
}
|
||||
|
||||
private void reset_notMagnifying_noStateChangeButInvokeCallback(int displayId) {
|
||||
register(displayId);
|
||||
|
||||
assertFalse(mFullScreenMagnificationController.reset(displayId, mEndCallback));
|
||||
assertFalse(mFullScreenMagnificationController.reset(displayId, mAnimationCallback));
|
||||
mMessageCapturingHandler.sendAllMessages();
|
||||
|
||||
verify(mMockAms, never()).notifyMagnificationChanged(eq(displayId),
|
||||
any(Region.class), anyFloat(), anyFloat(), anyFloat());
|
||||
verify(mEndCallback).run();
|
||||
verify(mAnimationCallback).onResult(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReset_Magnifying_resetsMagnificationAndInvokeLastEndCallback() {
|
||||
public void testReset_Magnifying_resetsMagnificationAndInvokeCallbacks() {
|
||||
for (int i = 0; i < DISPLAY_COUNT; i++) {
|
||||
reset_Magnifying_resetsMagnificationAndInvokeLastEndCallback(i);
|
||||
reset_Magnifying_resetsMagnificationAndInvokeCallbacks(i);
|
||||
}
|
||||
}
|
||||
|
||||
private void reset_Magnifying_resetsMagnificationAndInvokeLastEndCallback(int displayId) {
|
||||
private void reset_Magnifying_resetsMagnificationAndInvokeCallbacks(int displayId) {
|
||||
register(displayId);
|
||||
float scale = 2.5f;
|
||||
PointF firstCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
|
||||
assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId,
|
||||
scale, firstCenter.x, firstCenter.y, mEndCallback, SERVICE_ID_1));
|
||||
scale, firstCenter.x, firstCenter.y, mAnimationCallback, SERVICE_ID_1));
|
||||
mMessageCapturingHandler.sendAllMessages();
|
||||
Mockito.reset(mMockValueAnimator);
|
||||
// Stubs the logic after the animation is started.
|
||||
doAnswer(invocation -> {
|
||||
mStateListener.onAnimationCancel(mMockValueAnimator);
|
||||
mStateListener.onAnimationEnd(mMockValueAnimator);
|
||||
return null;
|
||||
}).when(mMockValueAnimator).cancel();
|
||||
@@ -713,13 +712,14 @@ public class FullScreenMagnificationControllerTest {
|
||||
float fraction = 0.33f;
|
||||
when(mMockValueAnimator.getAnimatedFraction()).thenReturn(fraction);
|
||||
mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
|
||||
Runnable lastEndCallback = Mockito.mock(Runnable.class);
|
||||
MagnificationAnimationCallback lastAnimationCallback = Mockito.mock(
|
||||
MagnificationAnimationCallback.class);
|
||||
|
||||
assertTrue(mFullScreenMagnificationController.reset(displayId, lastEndCallback));
|
||||
assertTrue(mFullScreenMagnificationController.reset(displayId, lastAnimationCallback));
|
||||
mMessageCapturingHandler.sendAllMessages();
|
||||
|
||||
// Verify expected actions.
|
||||
verify(mEndCallback, never()).run();
|
||||
verify(mAnimationCallback).onResult(false);
|
||||
verify(mMockValueAnimator).start();
|
||||
verify(mMockValueAnimator).cancel();
|
||||
|
||||
@@ -729,7 +729,7 @@ public class FullScreenMagnificationControllerTest {
|
||||
mStateListener.onAnimationEnd(mMockValueAnimator);
|
||||
|
||||
assertFalse(mFullScreenMagnificationController.isMagnifying(DISPLAY_0));
|
||||
verify(lastEndCallback).run();
|
||||
verify(lastAnimationCallback).onResult(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1142,6 +1142,7 @@ public class FullScreenMagnificationControllerTest {
|
||||
verify(mMockValueAnimator).addListener(animatorListenerArgumentCaptor.capture());
|
||||
mStateListener = animatorListenerArgumentCaptor.getValue();
|
||||
Mockito.reset(mMockValueAnimator); // Ignore other initialization
|
||||
Mockito.reset(mAnimationCallback);
|
||||
}
|
||||
|
||||
private void zoomIn2xToMiddle(int displayId) {
|
||||
|
||||
Reference in New Issue
Block a user