Add WindowMagnificationAnimationController for animation
WindowMagnificationAnimationController provides same
functionality but it runs the animation while
enabling/disabling.
This new patch also fixs NPE excetion that happens
when device is in rotation but mirrorWindow is invisible.
Bug: 161669184 163026794 163035371
Test: atest com.android.systemui.accessibility
atest WindowMagnificationGestureHandlerTest
manual Test: enable window magnification to see it
2. close mirroe window and rotate the device
Change-Id: I4531f5c96ea4b91b287cc8c5ffc4c98fc9611dd5
This commit is contained in:
@@ -29,7 +29,7 @@ import android.view.accessibility.IWindowMagnificationConnectionCallback;
|
||||
oneway interface IWindowMagnificationConnection {
|
||||
|
||||
/**
|
||||
* Enables window magnification on specifed display with specified center and scale.
|
||||
* Enables window magnification on specified display with given center and scale and animation.
|
||||
*
|
||||
* @param displayId The logical display id.
|
||||
* @param scale magnification scale.
|
||||
@@ -41,7 +41,7 @@ oneway interface IWindowMagnificationConnection {
|
||||
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY);
|
||||
|
||||
/**
|
||||
* Sets the scale of the window magnifier on specifed display.
|
||||
* Sets the scale of the window magnifier on specified display.
|
||||
*
|
||||
* @param displayId The logical display id.
|
||||
* @param scale magnification scale.
|
||||
@@ -49,14 +49,14 @@ oneway interface IWindowMagnificationConnection {
|
||||
void setScale(int displayId, float scale);
|
||||
|
||||
/**
|
||||
* Disables window magnification on specifed display.
|
||||
* Disables window magnification on specified display with animation.
|
||||
*
|
||||
* @param displayId The logical display id.
|
||||
*/
|
||||
void disableWindowMagnification(int displayId);
|
||||
|
||||
/**
|
||||
* Moves the window magnifier on the specifed display.
|
||||
* Moves the window magnifier on the specified display. It has no effect while animating.
|
||||
*
|
||||
* @param offsetX the amount in pixels to offset the window magnifier in the X direction, in
|
||||
* current screen pixels.
|
||||
|
||||
@@ -53,8 +53,8 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
|
||||
ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_ORIENTATION;
|
||||
|
||||
@VisibleForTesting
|
||||
protected WindowMagnificationController mWindowMagnificationController;
|
||||
protected final ModeSwitchesController mModeSwitchesController;
|
||||
protected WindowMagnificationAnimationController mWindowMagnificationAnimationController;
|
||||
private final ModeSwitchesController mModeSwitchesController;
|
||||
private final Handler mHandler;
|
||||
private final AccessibilityManager mAccessibilityManager;
|
||||
private final CommandQueue mCommandQueue;
|
||||
@@ -72,6 +72,11 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
|
||||
Context.ACCESSIBILITY_SERVICE);
|
||||
mCommandQueue = commandQueue;
|
||||
mModeSwitchesController = modeSwitchesController;
|
||||
final WindowMagnificationController controller = new WindowMagnificationController(mContext,
|
||||
mHandler, new SfVsyncFrameCallbackProvider(), null,
|
||||
new SurfaceControl.Transaction(), this);
|
||||
mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
|
||||
mContext, controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,9 +86,7 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
|
||||
return;
|
||||
}
|
||||
mLastConfiguration.setTo(newConfig);
|
||||
if (mWindowMagnificationController != null) {
|
||||
mWindowMagnificationController.onConfigurationChanged(configDiff);
|
||||
}
|
||||
mWindowMagnificationAnimationController.onConfigurationChanged(configDiff);
|
||||
if (mModeSwitchesController != null) {
|
||||
mModeSwitchesController.onConfigurationChanged(configDiff);
|
||||
}
|
||||
@@ -97,39 +100,25 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
|
||||
@MainThread
|
||||
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
|
||||
//TODO: b/144080869 support multi-display.
|
||||
if (mWindowMagnificationController == null) {
|
||||
mWindowMagnificationController = new WindowMagnificationController(mContext,
|
||||
mHandler,
|
||||
new SfVsyncFrameCallbackProvider(),
|
||||
null, new SurfaceControl.Transaction(),
|
||||
this);
|
||||
}
|
||||
mWindowMagnificationController.enableWindowMagnification(scale, centerX, centerY);
|
||||
mWindowMagnificationAnimationController.enableWindowMagnification(scale, centerX, centerY);
|
||||
}
|
||||
|
||||
@MainThread
|
||||
void setScale(int displayId, float scale) {
|
||||
//TODO: b/144080869 support multi-display.
|
||||
if (mWindowMagnificationController != null) {
|
||||
mWindowMagnificationController.setScale(scale);
|
||||
}
|
||||
mWindowMagnificationAnimationController.setScale(scale);
|
||||
}
|
||||
|
||||
@MainThread
|
||||
void moveWindowMagnifier(int displayId, float offsetX, float offsetY) {
|
||||
//TODO: b/144080869 support multi-display.
|
||||
if (mWindowMagnificationController != null) {
|
||||
mWindowMagnificationController.moveWindowMagnifier(offsetX, offsetY);
|
||||
}
|
||||
mWindowMagnificationAnimationController.moveWindowMagnifier(offsetX, offsetY);
|
||||
}
|
||||
|
||||
@MainThread
|
||||
void disableWindowMagnification(int displayId) {
|
||||
//TODO: b/144080869 support multi-display.
|
||||
if (mWindowMagnificationController != null) {
|
||||
mWindowMagnificationController.deleteWindowMagnification();
|
||||
}
|
||||
mWindowMagnificationController = null;
|
||||
mWindowMagnificationAnimationController.deleteWindowMagnification();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* 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 com.android.systemui.accessibility;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.IntDef;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.util.Log;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.systemui.R;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Provides same functionality of {@link WindowMagnificationController}. Some methods run with
|
||||
* the animation.
|
||||
*/
|
||||
class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUpdateListener,
|
||||
Animator.AnimatorListener {
|
||||
|
||||
private static final String TAG = "WindowMagnificationBridge";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({STATE_DISABLED, STATE_ENABLED, STATE_DISABLING, STATE_ENABLING})
|
||||
@interface MagnificationState {}
|
||||
|
||||
//The window magnification is disabled.
|
||||
private static final int STATE_DISABLED = 0;
|
||||
//The window magnification is enabled.
|
||||
private static final int STATE_ENABLED = 1;
|
||||
//The window magnification is going to be disabled when the animation is end.
|
||||
private static final int STATE_DISABLING = 2;
|
||||
//The animation is running for enabling the window magnification.
|
||||
private static final int STATE_ENABLING = 3;
|
||||
|
||||
private final WindowMagnificationController mController;
|
||||
private final ValueAnimator mValueAnimator;
|
||||
private final AnimationSpec mStartSpec = new AnimationSpec();
|
||||
private final AnimationSpec mEndSpec = new AnimationSpec();
|
||||
private final Context mContext;
|
||||
|
||||
@MagnificationState
|
||||
private int mState = STATE_DISABLED;
|
||||
|
||||
WindowMagnificationAnimationController(
|
||||
Context context, WindowMagnificationController controller) {
|
||||
this(context, controller, newValueAnimator(context.getResources()));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
WindowMagnificationAnimationController(Context context,
|
||||
WindowMagnificationController controller, ValueAnimator valueAnimator) {
|
||||
mContext = context;
|
||||
mController = controller;
|
||||
mValueAnimator = valueAnimator;
|
||||
mValueAnimator.addUpdateListener(this);
|
||||
mValueAnimator.addListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float)}
|
||||
* with transition animation. If the window magnification is not enabled, the scale will start
|
||||
* from 1.0 and the center won't be changed during the animation. If {@link #mState} is
|
||||
* {@code STATE_DISABLING}, the animation runs in reverse.
|
||||
*
|
||||
* @param scale the target scale, or {@link Float#NaN} to leave unchanged.
|
||||
* @param centerX the screen-relative X coordinate around which to center,
|
||||
* 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.
|
||||
*
|
||||
* @see #onAnimationUpdate(ValueAnimator)
|
||||
*/
|
||||
void enableWindowMagnification(float scale, float centerX, float centerY) {
|
||||
if (mState == STATE_ENABLING) {
|
||||
mValueAnimator.cancel();
|
||||
}
|
||||
setupEnableAnimationSpecs(scale, centerX, centerY);
|
||||
|
||||
if (mEndSpec.equals(mStartSpec)) {
|
||||
setState(STATE_ENABLED);
|
||||
} else {
|
||||
if (mState == STATE_DISABLING) {
|
||||
mValueAnimator.reverse();
|
||||
} else {
|
||||
mValueAnimator.start();
|
||||
}
|
||||
setState(STATE_ENABLING);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupEnableAnimationSpecs(float scale, float centerX, float centerY) {
|
||||
final float currentScale = mController.getScale();
|
||||
final float currentCenterX = mController.getCenterX();
|
||||
final float currentCenterY = mController.getCenterY();
|
||||
|
||||
if (mState == STATE_DISABLED) {
|
||||
//We don't need to offset the center during the animation.
|
||||
mStartSpec.set(/* scale*/ 1.0f, centerX, centerY);
|
||||
mEndSpec.set(Float.isNaN(scale) ? mContext.getResources().getInteger(
|
||||
R.integer.magnification_default_scale) : scale, centerX, centerY);
|
||||
} else {
|
||||
mStartSpec.set(currentScale, currentCenterX, currentCenterY);
|
||||
mEndSpec.set(Float.isNaN(scale) ? currentScale : scale,
|
||||
Float.isNaN(centerX) ? currentCenterX : centerX,
|
||||
Float.isNaN(centerY) ? currentCenterY : centerY);
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "SetupEnableAnimationSpecs : mStartSpec = " + mStartSpec + ", endSpec = "
|
||||
+ mEndSpec);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link WindowMagnificationController#setScale(float)}. If the animation is
|
||||
* running, it has no effect.
|
||||
*/
|
||||
void setScale(float scale) {
|
||||
if (mValueAnimator.isRunning()) {
|
||||
return;
|
||||
}
|
||||
mController.setScale(scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link WindowMagnificationController#deleteWindowMagnification()}} with transition
|
||||
* animation. If the window magnification is enabling, it runs the animation in reverse.
|
||||
*/
|
||||
void deleteWindowMagnification() {
|
||||
if (mState == STATE_DISABLED || mState == STATE_DISABLING) {
|
||||
return;
|
||||
}
|
||||
mStartSpec.set(/* scale*/ 1.0f, Float.NaN, Float.NaN);
|
||||
mEndSpec.set(/* scale*/ mController.getScale(), Float.NaN, Float.NaN);
|
||||
|
||||
mValueAnimator.reverse();
|
||||
setState(STATE_DISABLING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link WindowMagnificationController#moveWindowMagnifier(float, float)}. If the
|
||||
* animation is running, it has no effect.
|
||||
* @param offsetX the amount in pixels to offset the window magnifier in the X direction, in
|
||||
* current screen pixels.
|
||||
* @param offsetY the amount in pixels to offset the window magnifier in the Y direction, in
|
||||
* current screen pixels.
|
||||
*/
|
||||
void moveWindowMagnifier(float offsetX, float offsetY) {
|
||||
if (mValueAnimator.isRunning()) {
|
||||
return;
|
||||
}
|
||||
mController.moveWindowMagnifier(offsetX, offsetY);
|
||||
}
|
||||
|
||||
void onConfigurationChanged(int configDiff) {
|
||||
mController.onConfigurationChanged(configDiff);
|
||||
}
|
||||
|
||||
private void setState(@MagnificationState int state) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "setState from " + mState + " to " + state);
|
||||
}
|
||||
mState = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mState == STATE_DISABLING) {
|
||||
mController.deleteWindowMagnification();
|
||||
setState(STATE_DISABLED);
|
||||
} else if (mState == STATE_ENABLING) {
|
||||
setState(STATE_ENABLED);
|
||||
} else {
|
||||
Log.w(TAG, "onAnimationEnd unexpected state:" + mState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
final float fract = animation.getAnimatedFraction();
|
||||
final float sentScale = mStartSpec.mScale + (mEndSpec.mScale - mStartSpec.mScale) * fract;
|
||||
final float centerX =
|
||||
mStartSpec.mCenterX + (mEndSpec.mCenterX - mStartSpec.mCenterX) * fract;
|
||||
final float centerY =
|
||||
mStartSpec.mCenterY + (mEndSpec.mCenterY - mStartSpec.mCenterY) * fract;
|
||||
mController.enableWindowMagnification(sentScale, centerX, centerY);
|
||||
}
|
||||
|
||||
private static ValueAnimator newValueAnimator(Resources resources) {
|
||||
final ValueAnimator valueAnimator = new ValueAnimator();
|
||||
valueAnimator.setDuration(
|
||||
resources.getInteger(com.android.internal.R.integer.config_longAnimTime));
|
||||
valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f));
|
||||
valueAnimator.setFloatValues(0.0f, 1.0f);
|
||||
return valueAnimator;
|
||||
}
|
||||
|
||||
private static class AnimationSpec {
|
||||
private float mScale = Float.NaN;
|
||||
private float mCenterX = Float.NaN;
|
||||
private float mCenterY = Float.NaN;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (other == null || getClass() != other.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final AnimationSpec s = (AnimationSpec) other;
|
||||
return mScale == s.mScale && mCenterX == s.mCenterX && mCenterY == s.mCenterY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (mScale != +0.0f ? Float.floatToIntBits(mScale) : 0);
|
||||
result = 31 * result + (mCenterX != +0.0f ? Float.floatToIntBits(mCenterX) : 0);
|
||||
result = 31 * result + (mCenterY != +0.0f ? Float.floatToIntBits(mCenterY) : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
void set(float scale, float centerX, float centerY) {
|
||||
mScale = scale;
|
||||
mCenterX = centerX;
|
||||
mCenterY = centerY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AnimationSpec{"
|
||||
+ "mScale=" + mScale
|
||||
+ ", mCenterX=" + mCenterX
|
||||
+ ", mCenterY=" + mCenterY
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,7 +150,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
|
||||
mMirrorViewGeometryVsyncCallback =
|
||||
l -> {
|
||||
if (mMirrorView != null && mMirrorSurface != null) {
|
||||
if (isWindowVisible() && mMirrorSurface != null) {
|
||||
calculateSourceBounds(mMagnificationFrame, mScale);
|
||||
// The final destination for the magnification surface should be at 0,0
|
||||
// since the ViewRootImpl's position will change
|
||||
@@ -203,13 +203,13 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
* @param configDiff a bit mask of the differences between the configurations
|
||||
*/
|
||||
void onConfigurationChanged(int configDiff) {
|
||||
if (!isWindowVisible()) {
|
||||
return;
|
||||
}
|
||||
if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
|
||||
updateDimensions();
|
||||
// TODO(b/145780606): update toggle button UI.
|
||||
if (mMirrorView != null) {
|
||||
mWm.removeView(mMirrorView);
|
||||
createMirrorWindow();
|
||||
}
|
||||
mWm.removeView(mMirrorView);
|
||||
createMirrorWindow();
|
||||
} else if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
|
||||
onRotate();
|
||||
}
|
||||
@@ -502,7 +502,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
/**
|
||||
* Enables window magnification with specified parameters.
|
||||
*
|
||||
* @param scale the target scale
|
||||
* @param scale the target scale, or {@link Float#NaN} to leave unchanged
|
||||
* @param centerX the screen-relative X coordinate around which to center,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
* @param centerY the screen-relative Y coordinate around which to center,
|
||||
@@ -513,10 +513,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
: centerX - mMagnificationFrame.exactCenterX();
|
||||
final float offsetY = Float.isNaN(centerY) ? 0
|
||||
: centerY - mMagnificationFrame.exactCenterY();
|
||||
mScale = scale;
|
||||
mScale = Float.isNaN(scale) ? mScale : scale;
|
||||
setMagnificationFrameBoundary();
|
||||
updateMagnificationFramePosition((int) offsetX, (int) offsetY);
|
||||
if (mMirrorView == null) {
|
||||
if (!isWindowVisible()) {
|
||||
createMirrorWindow();
|
||||
showControls();
|
||||
} else {
|
||||
@@ -527,10 +527,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
/**
|
||||
* Sets the scale of the magnified region if it's visible.
|
||||
*
|
||||
* @param scale the target scale
|
||||
* @param scale the target scale, or {@link Float#NaN} to leave unchanged
|
||||
*/
|
||||
void setScale(float scale) {
|
||||
if (mMirrorView == null || mScale == scale) {
|
||||
if (!isWindowVisible() || mScale == scale) {
|
||||
return;
|
||||
}
|
||||
enableWindowMagnification(scale, Float.NaN, Float.NaN);
|
||||
@@ -552,4 +552,35 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
modifyWindowMagnification(mTransaction);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scale.
|
||||
* @return {@link Float#NaN} if the window is invisible.
|
||||
*/
|
||||
float getScale() {
|
||||
return isWindowVisible() ? mScale : Float.NaN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the screen-relative X coordinate of the center of the magnified bounds.
|
||||
*
|
||||
* @return the X coordinate. {@link Float#NaN} if the window is invisible.
|
||||
*/
|
||||
float getCenterX() {
|
||||
return isWindowVisible() ? mMagnificationFrame.exactCenterX() : Float.NaN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the screen-relative Y coordinate of the center of the magnified bounds.
|
||||
*
|
||||
* @return the Y coordinate. {@link Float#NaN} if the window is invisible.
|
||||
*/
|
||||
float getCenterY() {
|
||||
return isWindowVisible() ? mMagnificationFrame.exactCenterY() : Float.NaN;
|
||||
}
|
||||
|
||||
//The window is visible when it is existed.
|
||||
private boolean isWindowVisible() {
|
||||
return mMirrorView != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.content.Context;
|
||||
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.IWindowMagnificationConnection;
|
||||
@@ -47,6 +48,7 @@ import org.mockito.MockitoAnnotations;
|
||||
*/
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
public class IWindowMagnificationConnectionTest extends SysuiTestCase {
|
||||
|
||||
private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
|
||||
@@ -57,7 +59,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private IWindowMagnificationConnectionCallback mConnectionCallback;
|
||||
@Mock
|
||||
private WindowMagnificationController mWindowMagnificationController;
|
||||
private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
|
||||
@Mock
|
||||
private ModeSwitchesController mModeSwitchesController;
|
||||
private IWindowMagnificationConnection mIWindowMagnificationConnection;
|
||||
@@ -74,7 +76,8 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
|
||||
any(IWindowMagnificationConnection.class));
|
||||
mWindowMagnification = new WindowMagnification(getContext(),
|
||||
getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController);
|
||||
mWindowMagnification.mWindowMagnificationController = mWindowMagnificationController;
|
||||
mWindowMagnification.mWindowMagnificationAnimationController =
|
||||
mWindowMagnificationAnimationController;
|
||||
mWindowMagnification.requestWindowMagnificationConnection(true);
|
||||
assertNotNull(mIWindowMagnificationConnection);
|
||||
mIWindowMagnificationConnection.setConnectionCallback(mConnectionCallback);
|
||||
@@ -86,7 +89,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
|
||||
Float.NaN);
|
||||
waitForIdleSync();
|
||||
|
||||
verify(mWindowMagnificationController).enableWindowMagnification(3.0f, Float.NaN,
|
||||
verify(mWindowMagnificationAnimationController).enableWindowMagnification(3.0f, Float.NaN,
|
||||
Float.NaN);
|
||||
}
|
||||
|
||||
@@ -99,7 +102,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
|
||||
mIWindowMagnificationConnection.disableWindowMagnification(TEST_DISPLAY);
|
||||
waitForIdleSync();
|
||||
|
||||
verify(mWindowMagnificationController).deleteWindowMagnification();
|
||||
verify(mWindowMagnificationAnimationController).deleteWindowMagnification();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -107,7 +110,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
|
||||
mIWindowMagnificationConnection.setScale(TEST_DISPLAY, 3.0f);
|
||||
waitForIdleSync();
|
||||
|
||||
verify(mWindowMagnificationController).setScale(3.0f);
|
||||
verify(mWindowMagnificationAnimationController).setScale(3.0f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -115,7 +118,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
|
||||
mIWindowMagnificationConnection.moveWindowMagnifier(TEST_DISPLAY, 100f, 200f);
|
||||
waitForIdleSync();
|
||||
|
||||
verify(mWindowMagnificationController).moveWindowMagnifier(100f, 200f);
|
||||
verify(mWindowMagnificationAnimationController).moveWindowMagnifier(100f, 200f);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* 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 com.android.systemui.accessibility;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||
import static org.mockito.Mockito.atLeast;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.MediumTest;
|
||||
|
||||
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
|
||||
@MediumTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
|
||||
private static final float DEFAULT_SCALE = 3.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 AtomicReference<Float> mCurrentScale = new AtomicReference<>((float) 0);
|
||||
private AtomicReference<Float> mCurrentCenterX = new AtomicReference<>((float) 0);
|
||||
private AtomicReference<Float> mCurrentCenterY = new AtomicReference<>((float) 0);
|
||||
private ArgumentCaptor<Float> mScaleCaptor = ArgumentCaptor.forClass(Float.class);
|
||||
private ArgumentCaptor<Float> mCenterXCaptor = ArgumentCaptor.forClass(Float.class);
|
||||
private ArgumentCaptor<Float> mCenterYCaptor = ArgumentCaptor.forClass(Float.class);
|
||||
|
||||
@Mock
|
||||
Handler mHandler;
|
||||
@Mock
|
||||
SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
|
||||
@Mock
|
||||
WindowMagnifierCallback mWindowMagnifierCallback;
|
||||
|
||||
private SpyWindowMagnificationController mController;
|
||||
private WindowMagnificationController mSpyController;
|
||||
private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
|
||||
private Instrumentation mInstrumentation;
|
||||
private long mWaitingAnimationPeriod;
|
||||
private long mWaitIntermediateAnimationPeriod;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
mWaitingAnimationPeriod = ANIMATION_DURATION_MS + 50;
|
||||
mWaitIntermediateAnimationPeriod = ANIMATION_DURATION_MS / 2;
|
||||
mController = new SpyWindowMagnificationController(mContext, mHandler,
|
||||
mSfVsyncFrameProvider, null, new SurfaceControl.Transaction(),
|
||||
mWindowMagnifierCallback);
|
||||
mSpyController = mController.getSpyController();
|
||||
mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
|
||||
mContext, mController, newValueAnimator());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableWindowMagnification_disabled_expectedStartAndEndValues() {
|
||||
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
|
||||
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnification(
|
||||
mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture());
|
||||
verifyStartValue(mScaleCaptor, 1.0f);
|
||||
verifyStartValue(mCenterXCaptor, DEFAULT_CENTER_X);
|
||||
verifyStartValue(mCenterYCaptor, DEFAULT_CENTER_Y);
|
||||
verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableWindowMagnification_enabling_expectedStartAndEndValues() {
|
||||
enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
|
||||
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);
|
||||
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());
|
||||
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableWindowMagnification_disabling_expectedStartAndEndValues() {
|
||||
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
|
||||
deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
|
||||
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);
|
||||
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());
|
||||
//Animating in reverse, so we only check if the start values are greater than current.
|
||||
assertTrue(mScaleCaptor.getAllValues().get(0) > mCurrentScale.get());
|
||||
assertEquals(targetScale, mScaleCaptor.getValue(), 0f);
|
||||
assertTrue(mCenterXCaptor.getAllValues().get(0) > mCurrentCenterX.get());
|
||||
assertEquals(targetCenterX, mCenterXCaptor.getValue(), 0f);
|
||||
assertTrue(mCenterYCaptor.getAllValues().get(0) > mCurrentCenterY.get());
|
||||
assertEquals(targetCenterY, mCenterYCaptor.getValue(), 0f);
|
||||
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableWindowMagnificationWithSameScale_doNothing() {
|
||||
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
|
||||
|
||||
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
|
||||
|
||||
verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
|
||||
anyFloat());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setScale_enabled_expectedScale() {
|
||||
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
|
||||
|
||||
mInstrumentation.runOnMainSync(
|
||||
() -> mWindowMagnificationAnimationController.setScale(DEFAULT_SCALE + 1));
|
||||
|
||||
verify(mSpyController).setScale(DEFAULT_SCALE + 1);
|
||||
verifyFinalSpec(DEFAULT_SCALE + 1, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteWindowMagnification_enabled_expectedStartAndEndValues() {
|
||||
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
|
||||
|
||||
deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
|
||||
|
||||
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);
|
||||
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteWindowMagnification_disabled_doNothing() {
|
||||
deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
|
||||
|
||||
Mockito.verifyNoMoreInteractions(mSpyController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteWindowMagnification_enabling_checkStartAndEndValues() {
|
||||
enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
|
||||
|
||||
//It just reverse the animation, so we don't need to wait the whole duration.
|
||||
mInstrumentation.runOnMainSync(
|
||||
() -> {
|
||||
Mockito.reset(mSpyController);
|
||||
mWindowMagnificationAnimationController.deleteWindowMagnification();
|
||||
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());
|
||||
verify(mSpyController).deleteWindowMagnification();
|
||||
|
||||
//The animation is in verse, so we only check the start values should no be greater than
|
||||
// the current one.
|
||||
assertTrue(mScaleCaptor.getAllValues().get(0) <= mCurrentScale.get());
|
||||
assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
|
||||
verifyStartValue(mCenterXCaptor, Float.NaN);
|
||||
verifyStartValue(mCenterYCaptor, Float.NaN);
|
||||
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteWindowMagnification_disabling_checkStartAndValues() {
|
||||
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
|
||||
deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
|
||||
|
||||
deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void moveWindowMagnifier_enabled() {
|
||||
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
|
||||
|
||||
mInstrumentation.runOnMainSync(
|
||||
() -> mWindowMagnificationAnimationController.moveWindowMagnifier(100f, 200f));
|
||||
|
||||
verify(mSpyController).moveWindowMagnifier(100f, 200f);
|
||||
verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + 100f, DEFAULT_CENTER_Y + 100f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onConfigurationChanged_passThrough() {
|
||||
mWindowMagnificationAnimationController.onConfigurationChanged(100);
|
||||
|
||||
verify(mSpyController).onConfigurationChanged(100);
|
||||
}
|
||||
private void verifyFinalSpec(float expectedScale, float expectedCenterX,
|
||||
float expectedCenterY) {
|
||||
assertEquals(expectedScale, mController.getScale(), 0f);
|
||||
assertEquals(expectedCenterX, mController.getCenterX(), 0f);
|
||||
assertEquals(expectedCenterY, mController.getCenterY(), 0f);
|
||||
}
|
||||
|
||||
private void enableWindowMagnificationAndWaitAnimating(long duration) {
|
||||
mInstrumentation.runOnMainSync(
|
||||
() -> {
|
||||
Mockito.reset(mSpyController);
|
||||
mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
|
||||
DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
|
||||
});
|
||||
SystemClock.sleep(duration);
|
||||
}
|
||||
|
||||
private void deleteWindowMagnificationAndWaitAnimating(long duration) {
|
||||
mInstrumentation.runOnMainSync(
|
||||
() -> {
|
||||
resetMockObjects();
|
||||
mWindowMagnificationAnimationController.deleteWindowMagnification();
|
||||
});
|
||||
SystemClock.sleep(duration);
|
||||
}
|
||||
|
||||
private void verifyStartValue(ArgumentCaptor<Float> captor, float startValue) {
|
||||
assertEquals(startValue, captor.getAllValues().get(0), 0f);
|
||||
}
|
||||
|
||||
private void resetMockObjects() {
|
||||
Mockito.reset(mSpyController);
|
||||
}
|
||||
|
||||
/**
|
||||
* It observes the methods in {@link WindowMagnificationController} since we couldn't spy it
|
||||
* directly.
|
||||
*/
|
||||
private static class SpyWindowMagnificationController extends WindowMagnificationController {
|
||||
private WindowMagnificationController mSpyController;
|
||||
|
||||
SpyWindowMagnificationController(Context context, Handler handler,
|
||||
SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
|
||||
MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
|
||||
WindowMagnifierCallback callback) {
|
||||
super(context, handler, sfVsyncFrameProvider, mirrorWindowControl, transaction,
|
||||
callback);
|
||||
mSpyController = Mockito.mock(WindowMagnificationController.class);
|
||||
}
|
||||
|
||||
WindowMagnificationController getSpyController() {
|
||||
return mSpyController;
|
||||
}
|
||||
|
||||
@Override
|
||||
void enableWindowMagnification(float scale, float centerX, float centerY) {
|
||||
super.enableWindowMagnification(scale, centerX, centerY);
|
||||
mSpyController.enableWindowMagnification(scale, centerX, centerY);
|
||||
}
|
||||
|
||||
@Override
|
||||
void deleteWindowMagnification() {
|
||||
super.deleteWindowMagnification();
|
||||
mSpyController.deleteWindowMagnification();
|
||||
}
|
||||
|
||||
@Override
|
||||
void moveWindowMagnifier(float offsetX, float offsetY) {
|
||||
super.moveWindowMagnifier(offsetX, offsetX);
|
||||
mSpyController.moveWindowMagnifier(offsetX, offsetY);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setScale(float scale) {
|
||||
super.setScale(scale);
|
||||
mSpyController.setScale(scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onConfigurationChanged(int configDiff) {
|
||||
super.onConfigurationChanged(configDiff);
|
||||
mSpyController.onConfigurationChanged(configDiff);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static ValueAnimator newValueAnimator() {
|
||||
final ValueAnimator valueAnimator = new ValueAnimator();
|
||||
valueAnimator.setDuration(ANIMATION_DURATION_MS);
|
||||
valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f));
|
||||
valueAnimator.setFloatValues(0.0f, 1.0f);
|
||||
return valueAnimator;
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package com.android.systemui.accessibility;
|
||||
|
||||
import static android.view.Choreographer.FrameCallback;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
@@ -26,8 +27,12 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.os.Handler;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.view.Display;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
@@ -41,6 +46,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SmallTest
|
||||
@@ -57,12 +63,14 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
WindowMagnifierCallback mWindowMagnifierCallback;
|
||||
@Mock
|
||||
SurfaceControl.Transaction mTransaction;
|
||||
private Context mContext;
|
||||
private WindowMagnificationController mWindowMagnificationController;
|
||||
private Instrumentation mInstrumentation;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = Mockito.spy(getContext());
|
||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
doAnswer(invocation -> {
|
||||
FrameCallback callback = invocation.getArgument(0);
|
||||
@@ -73,8 +81,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
when(mTransaction.remove(any())).thenReturn(mTransaction);
|
||||
when(mTransaction.setGeometry(any(), any(), any(),
|
||||
anyInt())).thenReturn(mTransaction);
|
||||
|
||||
mWindowMagnificationController = new WindowMagnificationController(getContext(),
|
||||
mWindowMagnificationController = new WindowMagnificationController(mContext,
|
||||
mHandler, mSfVsyncFrameProvider,
|
||||
mMirrorWindowControl, mTransaction, mWindowMagnifierCallback);
|
||||
verify(mMirrorWindowControl).setWindowDelegate(
|
||||
@@ -83,9 +90,8 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.deleteWindowMagnification();
|
||||
});
|
||||
mInstrumentation.runOnMainSync(
|
||||
() -> mWindowMagnificationController.deleteWindowMagnification());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -121,4 +127,27 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
|
||||
verify(mSfVsyncFrameProvider, atLeastOnce()).postFrameCallback(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setScale_enabled_expectedValue() {
|
||||
mInstrumentation.runOnMainSync(
|
||||
() -> mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
Float.NaN));
|
||||
|
||||
mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.setScale(3.0f));
|
||||
|
||||
assertEquals(3.0f, mWindowMagnificationController.getScale(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onConfigurationChanged_disabled_withoutException() {
|
||||
Display display = Mockito.spy(mContext.getDisplay());
|
||||
when(display.getRotation()).thenReturn(Surface.ROTATION_90);
|
||||
when(mContext.getDisplay()).thenReturn(display);
|
||||
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
|
||||
mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.os.RemoteException;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.Display;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.IWindowMagnificationConnection;
|
||||
@@ -45,6 +46,7 @@ import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
public class WindowMagnificationTest extends SysuiTestCase {
|
||||
|
||||
@Mock
|
||||
|
||||
@@ -25,10 +25,12 @@ import static java.util.Arrays.copyOfRange;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.util.MathUtils;
|
||||
import android.util.Slog;
|
||||
import android.view.Display;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -90,6 +92,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
|
||||
|
||||
private MotionEventDispatcherDelegate mMotionEventDispatcherDelegate;
|
||||
private final int mDisplayId;
|
||||
private final Context mContext;
|
||||
private final Point mTempPoint = new Point();
|
||||
|
||||
private final Queue<MotionEvent> mDebugOutputEventHistory;
|
||||
|
||||
@@ -107,7 +111,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
|
||||
Slog.i(LOG_TAG,
|
||||
"WindowMagnificationGestureHandler() , displayId = " + displayId + ")");
|
||||
}
|
||||
|
||||
mContext = context;
|
||||
mWindowMagnificationMgr = windowMagnificationMgr;
|
||||
mDetectShortcutTrigger = detectShortcutTrigger;
|
||||
mDisplayId = displayId;
|
||||
@@ -184,7 +188,14 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
|
||||
if (!mDetectShortcutTrigger) {
|
||||
return;
|
||||
}
|
||||
toggleMagnification(Float.NaN, Float.NaN);
|
||||
final Point screenSize = mTempPoint;
|
||||
getScreenSize(mTempPoint);
|
||||
toggleMagnification(screenSize.x / 2.0f, screenSize.y / 2.0f);
|
||||
}
|
||||
|
||||
private void getScreenSize(Point outSize) {
|
||||
final Display display = mContext.getDisplay();
|
||||
display.getRealSize(outSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user