Support triple-tap and hold for window magnification.
1. Detect triple-tap and hold gesture. 2. Magnify the content at a user's tap location. 3. Offset the frame to the top-left position about a half of frame size 4. The definition and the implementation of WindowMagnificationController's getCenterX and getCenterY are different due to these patches. We need to correct them. (ref: b/207812394) Bug: 202465806 Test: atest IWindowMagnificationConnectionTest atest MagnificationControllerTest atest WindowMagnificationAnimationControllerTest (@Ignore) atest WindowMagnificationConnectionWrapperTest atest WindowMagnificationControllerTest atest WindowMagnificationGestureHandlerTest atest WindowMagnificationManagerTest Change-Id: I59bf8a3e35e42c963de1698bec915a4a590e5c5f
This commit is contained in:
@@ -38,9 +38,14 @@ 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 magnificationFrameOffsetRatioX Indicate the X coordinate offset between
|
||||
* frame position X and centerX
|
||||
* @param magnificationFrameOffsetRatioY Indicate the Y coordinate offset between
|
||||
* frame position Y and centerY
|
||||
* @param callback The callback called when the animation is completed or interrupted.
|
||||
*/
|
||||
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
|
||||
float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
|
||||
in IRemoteMagnificationAnimationCallback callback);
|
||||
|
||||
/**
|
||||
|
||||
@@ -158,12 +158,13 @@ public class WindowMagnification extends CoreStartable implements WindowMagnifie
|
||||
|
||||
@MainThread
|
||||
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
|
||||
float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
|
||||
@Nullable IRemoteMagnificationAnimationCallback callback) {
|
||||
final WindowMagnificationController windowMagnificationController =
|
||||
mMagnificationControllerSupplier.get(displayId);
|
||||
if (windowMagnificationController != null) {
|
||||
windowMagnificationController.enableWindowMagnification(scale, centerX,
|
||||
centerY, callback);
|
||||
windowMagnificationController.enableWindowMagnification(scale, centerX, centerY,
|
||||
magnificationFrameOffsetRatioX, magnificationFrameOffsetRatioY, callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
|
||||
private final ValueAnimator mValueAnimator;
|
||||
private final AnimationSpec mStartSpec = new AnimationSpec();
|
||||
private final AnimationSpec mEndSpec = new AnimationSpec();
|
||||
private float mMagnificationFrameOffsetRatioX = 0f;
|
||||
private float mMagnificationFrameOffsetRatioY = 0f;
|
||||
private final Context mContext;
|
||||
// Called when the animation is ended successfully without cancelling or mStartSpec and
|
||||
// mEndSpec are equal.
|
||||
@@ -88,7 +90,8 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float)}
|
||||
* Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float,
|
||||
* float, float, IRemoteMagnificationAnimationCallback)}
|
||||
* 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.
|
||||
@@ -106,16 +109,48 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
|
||||
*/
|
||||
void enableWindowMagnification(float scale, float centerX, float centerY,
|
||||
@Nullable IRemoteMagnificationAnimationCallback animationCallback) {
|
||||
enableWindowMagnification(scale, centerX, centerY, 0f, 0f, animationCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float,
|
||||
* float, float, IRemoteMagnificationAnimationCallback)}
|
||||
* 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 for magnification,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
* @param centerY The screen-relative Y coordinate around which to center for magnification,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
* @param magnificationFrameOffsetRatioX Indicate the X coordinate offset between
|
||||
* frame position X and centerX
|
||||
* @param magnificationFrameOffsetRatioY Indicate the Y coordinate offset between
|
||||
* frame position Y and centerY
|
||||
* @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,
|
||||
float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
|
||||
@Nullable IRemoteMagnificationAnimationCallback animationCallback) {
|
||||
if (mController == null) {
|
||||
return;
|
||||
}
|
||||
sendAnimationCallback(false);
|
||||
mMagnificationFrameOffsetRatioX = magnificationFrameOffsetRatioX;
|
||||
mMagnificationFrameOffsetRatioY = magnificationFrameOffsetRatioY;
|
||||
|
||||
// Enable window magnification without animation immediately.
|
||||
if (animationCallback == null) {
|
||||
if (mState == STATE_ENABLING || mState == STATE_DISABLING) {
|
||||
mValueAnimator.cancel();
|
||||
}
|
||||
mController.enableWindowMagnification(scale, centerX, centerY);
|
||||
mController.enableWindowMagnificationInternal(scale, centerX, centerY,
|
||||
mMagnificationFrameOffsetRatioX, mMagnificationFrameOffsetRatioY);
|
||||
setState(STATE_ENABLED);
|
||||
return;
|
||||
}
|
||||
@@ -123,7 +158,8 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
|
||||
setupEnableAnimationSpecs(scale, centerX, centerY);
|
||||
if (mEndSpec.equals(mStartSpec)) {
|
||||
if (mState == STATE_DISABLED) {
|
||||
mController.enableWindowMagnification(scale, centerX, centerY);
|
||||
mController.enableWindowMagnificationInternal(scale, centerX, centerY,
|
||||
mMagnificationFrameOffsetRatioX, mMagnificationFrameOffsetRatioY);
|
||||
} else if (mState == STATE_ENABLING || mState == STATE_DISABLING) {
|
||||
mValueAnimator.cancel();
|
||||
}
|
||||
@@ -273,7 +309,8 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
|
||||
mStartSpec.mCenterX + (mEndSpec.mCenterX - mStartSpec.mCenterX) * fract;
|
||||
final float centerY =
|
||||
mStartSpec.mCenterY + (mEndSpec.mCenterY - mStartSpec.mCenterY) * fract;
|
||||
mController.enableWindowMagnification(sentScale, centerX, centerY);
|
||||
mController.enableWindowMagnificationInternal(sentScale, centerX, centerY,
|
||||
mMagnificationFrameOffsetRatioX, mMagnificationFrameOffsetRatioY);
|
||||
}
|
||||
|
||||
private static ValueAnimator newValueAnimator(Resources resources) {
|
||||
|
||||
@@ -49,11 +49,13 @@ class WindowMagnificationConnectionImpl extends IWindowMagnificationConnection.S
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableWindowMagnification(int displayId, float scale, float centerX,
|
||||
float centerY, IRemoteMagnificationAnimationCallback callback) {
|
||||
public void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
|
||||
float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
|
||||
IRemoteMagnificationAnimationCallback callback) {
|
||||
mHandler.post(
|
||||
() -> mWindowMagnification.enableWindowMagnification(displayId, scale, centerX,
|
||||
centerY, callback));
|
||||
centerY, magnificationFrameOffsetRatioX,
|
||||
magnificationFrameOffsetRatioY, callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -95,17 +95,46 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
@Surface.Rotation
|
||||
@VisibleForTesting
|
||||
int mRotation;
|
||||
private final Rect mMagnificationFrame = new Rect();
|
||||
private final SurfaceControl.Transaction mTransaction;
|
||||
|
||||
private final WindowManager mWm;
|
||||
|
||||
private float mScale;
|
||||
|
||||
/**
|
||||
* MagnificationFrame represents the bound of {@link #mMirrorSurface} and is constrained
|
||||
* by the {@link #mMagnificationFrameBoundary}.
|
||||
* We use MagnificationFrame to calculate the position of {@link #mMirrorView}.
|
||||
* We combine MagnificationFrame with {@link #mMagnificationFrameOffsetX} and
|
||||
* {@link #mMagnificationFrameOffsetY} to calculate the position of {@link #mSourceBounds}.
|
||||
*/
|
||||
private final Rect mMagnificationFrame = new Rect();
|
||||
private final Rect mTmpRect = new Rect();
|
||||
|
||||
/**
|
||||
* MirrorViewBounds is the bound of the {@link #mMirrorView} which displays the magnified
|
||||
* content.
|
||||
* {@link #mMirrorView}'s center is equal to {@link #mMagnificationFrame}'s center.
|
||||
*/
|
||||
private final Rect mMirrorViewBounds = new Rect();
|
||||
|
||||
/**
|
||||
* SourceBound is the bound of the magnified region which projects the magnified content.
|
||||
* SourceBound's center is equal to the parameters centerX and centerY in
|
||||
* {@link WindowMagnificationController#enableWindowMagnificationInternal(float, float, float)}}
|
||||
* but it is calculated from {@link #mMagnificationFrame}'s center in the runtime.
|
||||
*/
|
||||
private final Rect mSourceBounds = new Rect();
|
||||
|
||||
/**
|
||||
* The relation of centers between {@link #mSourceBounds} and {@link #mMagnificationFrame} is
|
||||
* calculated in {@link #calculateSourceBounds(Rect, float)} and the equations are as following:
|
||||
* MagnificationFrame = SourceBound (e.g., centerX & centerY) + MagnificationFrameOffset
|
||||
* SourceBound = MagnificationFrame - MagnificationFrameOffset
|
||||
*/
|
||||
private int mMagnificationFrameOffsetX = 0;
|
||||
private int mMagnificationFrameOffsetY = 0;
|
||||
|
||||
// The root of the mirrored content
|
||||
private SurfaceControl mMirrorSurface;
|
||||
|
||||
@@ -123,6 +152,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
private final Runnable mMirrorViewRunnable;
|
||||
private final Runnable mUpdateStateDescriptionRunnable;
|
||||
private final Runnable mWindowInsetChangeRunnable;
|
||||
// MirrorView is the mirror window which displays the magnified content.
|
||||
private View mMirrorView;
|
||||
private SurfaceView mMirrorSurfaceView;
|
||||
private int mMirrorSurfaceMargin;
|
||||
@@ -339,7 +369,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
// window size changed not caused by rotation.
|
||||
if (isWindowVisible() && reCreateWindow) {
|
||||
deleteWindowMagnification();
|
||||
enableWindowMagnification(Float.NaN, Float.NaN, Float.NaN);
|
||||
enableWindowMagnificationInternal(Float.NaN, Float.NaN, Float.NaN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -633,6 +663,26 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
int top = displayFrame.top + (halfHeight - (int) (halfHeight / scale));
|
||||
int bottom = displayFrame.bottom - (halfHeight - (int) (halfHeight / scale));
|
||||
mSourceBounds.set(left, top, right, bottom);
|
||||
|
||||
// SourceBound's center is equal to center[X,Y] but calculated from MagnificationFrame's
|
||||
// center. The relation between SourceBound and MagnificationFrame is as following:
|
||||
// MagnificationFrame = SourceBound (center[X,Y]) + MagnificationFrameOffset
|
||||
// SourceBound = MagnificationFrame - MagnificationFrameOffset
|
||||
mSourceBounds.offset(-mMagnificationFrameOffsetX, -mMagnificationFrameOffsetY);
|
||||
|
||||
if (mSourceBounds.left < 0) {
|
||||
mSourceBounds.offsetTo(0, mSourceBounds.top);
|
||||
} else if (mSourceBounds.right > mWindowBounds.width()) {
|
||||
mSourceBounds.offsetTo(mWindowBounds.width() - mSourceBounds.width(),
|
||||
mSourceBounds.top);
|
||||
}
|
||||
|
||||
if (mSourceBounds.top < 0) {
|
||||
mSourceBounds.offsetTo(mSourceBounds.left, 0);
|
||||
} else if (mSourceBounds.bottom > mWindowBounds.height()) {
|
||||
mSourceBounds.offsetTo(mSourceBounds.left,
|
||||
mWindowBounds.height() - mSourceBounds.height());
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateMagnificationFrameBoundary() {
|
||||
@@ -646,11 +696,31 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
final int scaledWidth = (int) (halfWidth / mScale);
|
||||
// The scaled half height of magnified region.
|
||||
final int scaledHeight = (int) (halfHeight / mScale);
|
||||
final int exceededWidth = halfWidth - scaledWidth;
|
||||
final int exceededHeight = halfHeight - scaledHeight;
|
||||
|
||||
mMagnificationFrameBoundary.set(-exceededWidth, -exceededHeight,
|
||||
mWindowBounds.width() + exceededWidth, mWindowBounds.height() + exceededHeight);
|
||||
// MagnificationFrameBoundary constrain the space of MagnificationFrame, and it also has
|
||||
// to leave enough space for SourceBound to magnify the whole screen space.
|
||||
// However, there is an offset between SourceBound and MagnificationFrame.
|
||||
// The relation between SourceBound and MagnificationFrame is as following:
|
||||
// SourceBound = MagnificationFrame - MagnificationFrameOffset
|
||||
// Therefore, we have to adjust the exceededBoundary based on the offset.
|
||||
//
|
||||
// We have to increase the offset space for the SourceBound edges which are located in
|
||||
// the MagnificationFrame. For example, if the offsetX and offsetY are negative, which
|
||||
// means SourceBound is at right-bottom size of MagnificationFrame, the left and top
|
||||
// edges of SourceBound are located in MagnificationFrame. So, we have to leave extra
|
||||
// offset space at left and top sides and don't have to leave extra space at right and
|
||||
// bottom sides.
|
||||
final int exceededLeft = Math.max(halfWidth - scaledWidth - mMagnificationFrameOffsetX, 0);
|
||||
final int exceededRight = Math.max(halfWidth - scaledWidth + mMagnificationFrameOffsetX, 0);
|
||||
final int exceededTop = Math.max(halfHeight - scaledHeight - mMagnificationFrameOffsetY, 0);
|
||||
final int exceededBottom = Math.max(halfHeight - scaledHeight + mMagnificationFrameOffsetY,
|
||||
0);
|
||||
|
||||
mMagnificationFrameBoundary.set(
|
||||
-exceededLeft,
|
||||
-exceededTop,
|
||||
mWindowBounds.width() + exceededRight,
|
||||
mWindowBounds.height() + exceededBottom);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -711,24 +781,30 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float)}
|
||||
* Wraps {@link WindowMagnificationController#enableWindowMagnificationInternal(float, float,
|
||||
* 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 animator 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,
|
||||
* @param centerX The screen-relative X coordinate around which to center for magnification,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
* @param centerY The screen-relative Y coordinate around which to center,
|
||||
* @param centerY The screen-relative Y coordinate around which to center for magnification,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
* @param magnificationFrameOffsetRatioX Indicate the X coordinate offset
|
||||
* between frame position X and centerX
|
||||
* @param magnificationFrameOffsetRatioY Indicate the Y coordinate offset
|
||||
* between frame position Y and centerY
|
||||
* @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 enableWindowMagnification(float scale, float centerX, float centerY,
|
||||
float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
|
||||
@Nullable IRemoteMagnificationAnimationCallback animationCallback) {
|
||||
mAnimationController.enableWindowMagnification(scale, centerX,
|
||||
centerY, animationCallback);
|
||||
mAnimationController.enableWindowMagnification(scale, centerX, centerY,
|
||||
magnificationFrameOffsetRatioX, magnificationFrameOffsetRatioY, animationCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -738,21 +814,56 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
* be consistent with the behavior of display magnification.
|
||||
*
|
||||
* @param scale the target scale, or {@link Float#NaN} to leave unchanged
|
||||
* @param centerX the screen-relative X coordinate around which to center,
|
||||
* @param centerX the screen-relative X coordinate around which to center for magnification,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
* @param centerY the screen-relative Y coordinate around which to center,
|
||||
* @param centerY the screen-relative Y coordinate around which to center for magnification,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
*/
|
||||
void enableWindowMagnification(float scale, float centerX, float centerY) {
|
||||
void enableWindowMagnificationInternal(float scale, float centerX, float centerY) {
|
||||
enableWindowMagnificationInternal(scale, centerX, centerY, Float.NaN, Float.NaN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables window magnification with specified parameters. If the given scale is <strong>less
|
||||
* than or equal to 1.0f<strong>, then
|
||||
* {@link WindowMagnificationController#deleteWindowMagnification()} will be called instead to
|
||||
* be consistent with the behavior of display magnification.
|
||||
*
|
||||
* @param scale the target scale, or {@link Float#NaN} to leave unchanged
|
||||
* @param centerX the screen-relative X coordinate around which to center for magnification,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
* @param centerY the screen-relative Y coordinate around which to center for magnification,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
* @param magnificationFrameOffsetRatioX Indicate the X coordinate offset
|
||||
* between frame position X and centerX,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
* @param magnificationFrameOffsetRatioY Indicate the Y coordinate offset
|
||||
* between frame position Y and centerY,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
*/
|
||||
void enableWindowMagnificationInternal(float scale, float centerX, float centerY,
|
||||
float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY) {
|
||||
if (Float.compare(scale, 1.0f) <= 0) {
|
||||
deleteWindowMagnification();
|
||||
return;
|
||||
}
|
||||
|
||||
mMagnificationFrameOffsetX = Float.isNaN(magnificationFrameOffsetRatioX)
|
||||
? mMagnificationFrameOffsetX
|
||||
: (int) (mMagnificationFrame.width() / 2 * magnificationFrameOffsetRatioX);
|
||||
mMagnificationFrameOffsetY = Float.isNaN(magnificationFrameOffsetRatioY)
|
||||
? mMagnificationFrameOffsetY
|
||||
: (int) (mMagnificationFrame.height() / 2 * magnificationFrameOffsetRatioY);
|
||||
|
||||
// The relation of centers between SourceBound and MagnificationFrame is as following:
|
||||
// MagnificationFrame = SourceBound (e.g., centerX & centerY) + MagnificationFrameOffset
|
||||
final float newMagnificationFrameCenterX = centerX + mMagnificationFrameOffsetX;
|
||||
final float newMagnificationFrameCenterY = centerY + mMagnificationFrameOffsetY;
|
||||
|
||||
final float offsetX = Float.isNaN(centerX) ? 0
|
||||
: centerX - mMagnificationFrame.exactCenterX();
|
||||
: newMagnificationFrameCenterX - mMagnificationFrame.exactCenterX();
|
||||
final float offsetY = Float.isNaN(centerY) ? 0
|
||||
: centerY - mMagnificationFrame.exactCenterY();
|
||||
: newMagnificationFrameCenterY - mMagnificationFrame.exactCenterY();
|
||||
mScale = Float.isNaN(scale) ? mScale : scale;
|
||||
|
||||
calculateMagnificationFrameBoundary();
|
||||
@@ -774,7 +885,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
|
||||
if (mAnimationController.isAnimating() || !isWindowVisible() || mScale == scale) {
|
||||
return;
|
||||
}
|
||||
enableWindowMagnification(scale, Float.NaN, Float.NaN);
|
||||
enableWindowMagnificationInternal(scale, Float.NaN, Float.NaN);
|
||||
mHandler.removeCallbacks(mUpdateStateDescriptionRunnable);
|
||||
mHandler.postDelayed(mUpdateStateDescriptionRunnable, UPDATE_STATE_DESCRIPTION_DELAY_MS);
|
||||
}
|
||||
|
||||
@@ -100,11 +100,11 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void enableWindowMagnification_passThrough() throws RemoteException {
|
||||
mIWindowMagnificationConnection.enableWindowMagnification(TEST_DISPLAY, 3.0f, Float.NaN,
|
||||
Float.NaN, mAnimationCallback);
|
||||
Float.NaN, 0f, 0f, mAnimationCallback);
|
||||
waitForIdleSync();
|
||||
|
||||
verify(mWindowMagnificationController).enableWindowMagnification(eq(3.0f),
|
||||
eq(Float.NaN), eq(Float.NaN), eq(mAnimationCallback));
|
||||
eq(Float.NaN), eq(Float.NaN), eq(0f), eq(0f), eq(mAnimationCallback));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -110,7 +110,7 @@ public class TestableWindowManager implements WindowManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given window insets to the current window metics.
|
||||
* Sets the given window insets to the current window metrics.
|
||||
*
|
||||
* @param insets the window insets.
|
||||
*/
|
||||
|
||||
@@ -17,22 +17,27 @@
|
||||
package com.android.systemui.accessibility;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
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;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
|
||||
@@ -40,6 +45,7 @@ import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.LargeTest;
|
||||
|
||||
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.model.SysUiState;
|
||||
|
||||
@@ -56,7 +62,6 @@ import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
|
||||
@Ignore
|
||||
@LargeTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@@ -74,6 +79,8 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
private ArgumentCaptor<Float> mScaleCaptor = ArgumentCaptor.forClass(Float.class);
|
||||
private ArgumentCaptor<Float> mCenterXCaptor = ArgumentCaptor.forClass(Float.class);
|
||||
private ArgumentCaptor<Float> mCenterYCaptor = ArgumentCaptor.forClass(Float.class);
|
||||
private final ArgumentCaptor<Float> mOffsetXCaptor = ArgumentCaptor.forClass(Float.class);
|
||||
private final ArgumentCaptor<Float> mOffsetYCaptor = ArgumentCaptor.forClass(Float.class);
|
||||
|
||||
@Mock
|
||||
Handler mHandler;
|
||||
@@ -94,10 +101,16 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
private long mWaitingAnimationPeriod;
|
||||
private long mWaitIntermediateAnimationPeriod;
|
||||
|
||||
private TestableWindowManager mWindowManager;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
final WindowManager wm = mContext.getSystemService(WindowManager.class);
|
||||
mWindowManager = spy(new TestableWindowManager(wm));
|
||||
mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
|
||||
|
||||
mWaitingAnimationPeriod = 2 * ANIMATION_DURATION_MS;
|
||||
mWaitIntermediateAnimationPeriod = ANIMATION_DURATION_MS / 2;
|
||||
mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
|
||||
@@ -119,12 +132,15 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
throws RemoteException {
|
||||
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
|
||||
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnification(
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
|
||||
mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture());
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture(),
|
||||
mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
|
||||
verifyStartValue(mScaleCaptor, 1.0f);
|
||||
verifyStartValue(mCenterXCaptor, DEFAULT_CENTER_X);
|
||||
verifyStartValue(mCenterYCaptor, DEFAULT_CENTER_Y);
|
||||
verifyStartValue(mOffsetXCaptor, 0f);
|
||||
verifyStartValue(mOffsetYCaptor, 0f);
|
||||
verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
|
||||
verify(mAnimationCallback).onResult(true);
|
||||
}
|
||||
@@ -162,8 +178,8 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
});
|
||||
SystemClock.sleep(mWaitingAnimationPeriod);
|
||||
|
||||
verify(mSpyController).enableWindowMagnification(1, DEFAULT_CENTER_X,
|
||||
DEFAULT_CENTER_Y);
|
||||
verify(mSpyController).enableWindowMagnificationInternal(1, DEFAULT_CENTER_X,
|
||||
DEFAULT_CENTER_Y, 0f, 0f);
|
||||
verify(mAnimationCallback).onResult(true);
|
||||
}
|
||||
|
||||
@@ -187,11 +203,15 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
|
||||
SystemClock.sleep(mWaitingAnimationPeriod);
|
||||
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture());
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
|
||||
mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture(),
|
||||
mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
|
||||
verifyStartValue(mScaleCaptor, mCurrentScale.get());
|
||||
verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
|
||||
verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
|
||||
verifyStartValue(mOffsetXCaptor, 0f);
|
||||
verifyStartValue(mOffsetYCaptor, 0f);
|
||||
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
|
||||
verify(mAnimationCallback).onResult(false);
|
||||
verify(mAnimationCallback2).onResult(true);
|
||||
@@ -213,11 +233,15 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
|
||||
SystemClock.sleep(mWaitingAnimationPeriod);
|
||||
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture());
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
|
||||
mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture(),
|
||||
mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
|
||||
verifyStartValue(mScaleCaptor, mCurrentScale.get());
|
||||
verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
|
||||
verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
|
||||
verifyStartValue(mOffsetXCaptor, 0f);
|
||||
verifyStartValue(mOffsetYCaptor, 0f);
|
||||
// It presents the window magnification is disabled.
|
||||
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
|
||||
|
||||
@@ -256,7 +280,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
});
|
||||
SystemClock.sleep(mWaitingAnimationPeriod);
|
||||
|
||||
verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
|
||||
verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
|
||||
anyFloat());
|
||||
verify(mAnimationCallback).onResult(false);
|
||||
verify(mAnimationCallback2).onResult(true);
|
||||
@@ -286,9 +310,10 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
verify(mAnimationCallback).onResult(false);
|
||||
SystemClock.sleep(mWaitingAnimationPeriod);
|
||||
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnification(
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
|
||||
mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture());
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture(),
|
||||
mOffsetXCaptor.capture(), mOffsetYCaptor.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);
|
||||
@@ -336,7 +361,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
});
|
||||
SystemClock.sleep(mWaitingAnimationPeriod);
|
||||
|
||||
verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
|
||||
verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
|
||||
anyFloat());
|
||||
verify(mSpyController, never()).deleteWindowMagnification();
|
||||
verify(mAnimationCallback).onResult(false);
|
||||
@@ -362,15 +387,43 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
|
||||
SystemClock.sleep(mWaitingAnimationPeriod);
|
||||
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture());
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
|
||||
mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture(),
|
||||
mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
|
||||
verifyStartValue(mScaleCaptor, mCurrentScale.get());
|
||||
verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
|
||||
verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
|
||||
verifyStartValue(mOffsetXCaptor, 0f);
|
||||
verifyStartValue(mOffsetYCaptor, 0f);
|
||||
verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
|
||||
verify(mAnimationCallback2).onResult(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableWindowMagnificationWithOffset_expectedValues() {
|
||||
final float offsetRatio = -0.1f;
|
||||
final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
Mockito.reset(mSpyController);
|
||||
mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
|
||||
windowBounds.exactCenterX(), windowBounds.exactCenterY(),
|
||||
offsetRatio, offsetRatio, mAnimationCallback);
|
||||
});
|
||||
SystemClock.sleep(mWaitingAnimationPeriod);
|
||||
final View attachedView = mWindowManager.getAttachedView();
|
||||
assertNotNull(attachedView);
|
||||
final Rect mirrorViewBound = new Rect();
|
||||
final View mirrorView = attachedView.findViewById(R.id.surface_view);
|
||||
assertNotNull(mirrorView);
|
||||
mirrorView.getBoundsOnScreen(mirrorViewBound);
|
||||
|
||||
assertEquals(mirrorViewBound.exactCenterX() - windowBounds.exactCenterX(),
|
||||
Math.round(offsetRatio * mirrorViewBound.width() / 2), 0.1f);
|
||||
assertEquals(mirrorViewBound.exactCenterY() - windowBounds.exactCenterY(),
|
||||
Math.round(offsetRatio * mirrorViewBound.height() / 2), 0.1f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableWindowMagnificationWithSameScale_enabled_doNothingButInvokeCallback()
|
||||
throws RemoteException {
|
||||
@@ -378,7 +431,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
|
||||
enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
|
||||
|
||||
verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
|
||||
verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
|
||||
anyFloat());
|
||||
verify(mAnimationCallback).onResult(true);
|
||||
}
|
||||
@@ -390,11 +443,15 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
|
||||
deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
|
||||
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture());
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
|
||||
mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture(),
|
||||
mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
|
||||
verifyStartValue(mScaleCaptor, DEFAULT_SCALE);
|
||||
verifyStartValue(mCenterXCaptor, Float.NaN);
|
||||
verifyStartValue(mCenterYCaptor, Float.NaN);
|
||||
verifyStartValue(mOffsetXCaptor, 0f);
|
||||
verifyStartValue(mOffsetYCaptor, 0f);
|
||||
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
|
||||
verify(mAnimationCallback).onResult(true);
|
||||
}
|
||||
@@ -433,8 +490,10 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
mCurrentCenterY.set(mController.getCenterY());
|
||||
});
|
||||
SystemClock.sleep(mWaitingAnimationPeriod);
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture());
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
|
||||
mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture(),
|
||||
mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
|
||||
|
||||
//The animation is in verse, so we only check the start values should no be greater than
|
||||
// the current one.
|
||||
@@ -442,6 +501,8 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
|
||||
verifyStartValue(mCenterXCaptor, Float.NaN);
|
||||
verifyStartValue(mCenterYCaptor, Float.NaN);
|
||||
verifyStartValue(mOffsetXCaptor, 0f);
|
||||
verifyStartValue(mOffsetYCaptor, 0f);
|
||||
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
|
||||
verify(mAnimationCallback).onResult(false);
|
||||
verify(mAnimationCallback2).onResult(true);
|
||||
@@ -471,9 +532,13 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
|
||||
deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback2);
|
||||
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture());
|
||||
verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
|
||||
mScaleCaptor.capture(),
|
||||
mCenterXCaptor.capture(), mCenterYCaptor.capture(),
|
||||
mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
|
||||
assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
|
||||
verifyStartValue(mOffsetXCaptor, 0f);
|
||||
verifyStartValue(mOffsetYCaptor, 0f);
|
||||
verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
|
||||
verify(mAnimationCallback).onResult(false);
|
||||
verify(mAnimationCallback2).onResult(true);
|
||||
@@ -571,9 +636,18 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
@Override
|
||||
void enableWindowMagnification(float scale, float centerX, float centerY) {
|
||||
super.enableWindowMagnification(scale, centerX, centerY);
|
||||
mSpyController.enableWindowMagnification(scale, centerX, centerY);
|
||||
void enableWindowMagnificationInternal(float scale, float centerX, float centerY) {
|
||||
super.enableWindowMagnificationInternal(scale, centerX, centerY);
|
||||
mSpyController.enableWindowMagnificationInternal(scale, centerX, centerY);
|
||||
}
|
||||
|
||||
@Override
|
||||
void enableWindowMagnificationInternal(float scale, float centerX, float centerY,
|
||||
float magnificationOffsetFrameRatioX, float magnificationOffsetFrameRatioY) {
|
||||
super.enableWindowMagnificationInternal(scale, centerX, centerY,
|
||||
magnificationOffsetFrameRatioX, magnificationOffsetFrameRatioY);
|
||||
mSpyController.enableWindowMagnificationInternal(scale, centerX, centerY,
|
||||
magnificationOffsetFrameRatioX, magnificationOffsetFrameRatioY);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -146,7 +146,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void enableWindowMagnification_showControlAndNotifyBoundsChanged() {
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
|
||||
@@ -159,7 +159,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void enableWindowMagnification_systemGestureExclusionRectsIsSet() {
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
// Wait for Rects updated.
|
||||
@@ -180,7 +180,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
mMirrorWindowControl, mTransaction, mWindowMagnifierCallback, mSysUiState);
|
||||
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
controller.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
controller.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
|
||||
@@ -195,7 +195,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void deleteWindowMagnification_destroyControl() {
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
|
||||
@@ -213,7 +213,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
setSystemGestureInsets();
|
||||
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
bounds.bottom);
|
||||
});
|
||||
ReferenceTestUtils.waitForCondition(this::hasMagnificationOverlapFlag);
|
||||
@@ -229,7 +229,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void moveMagnifier_schedulesFrame() {
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
Float.NaN);
|
||||
mWindowMagnificationController.moveWindowMagnifier(100f, 100f);
|
||||
});
|
||||
@@ -246,8 +246,8 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
}).when(mHandler).postDelayed(any(Runnable.class), anyLong());
|
||||
|
||||
mInstrumentation.runOnMainSync(
|
||||
() -> mWindowMagnificationController.enableWindowMagnification(2.0f, Float.NaN,
|
||||
Float.NaN));
|
||||
() -> mWindowMagnificationController.enableWindowMagnificationInternal(2.0f,
|
||||
Float.NaN, Float.NaN));
|
||||
|
||||
mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.setScale(3.0f));
|
||||
|
||||
@@ -283,8 +283,8 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
final float displayWidth = windowBounds.width();
|
||||
final PointF magnifiedCenter = new PointF(center, center + 5f);
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, magnifiedCenter.x,
|
||||
magnifiedCenter.y);
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
|
||||
magnifiedCenter.x, magnifiedCenter.y);
|
||||
// Get the center again in case the center we set is out of screen.
|
||||
magnifiedCenter.set(mWindowMagnificationController.getCenterX(),
|
||||
mWindowMagnificationController.getCenterY());
|
||||
@@ -327,7 +327,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
testWindowBounds.set(testWindowBounds.left, testWindowBounds.top,
|
||||
testWindowBounds.right + 100, testWindowBounds.bottom + 100);
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
mWindowManager.setWindowBounds(testWindowBounds);
|
||||
@@ -347,7 +347,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void screenSizeIsChangedToLarge_enabled_windowSizeIsConstrained() {
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
final int screenSize = mContext.getResources().getDimensionPixelSize(
|
||||
@@ -369,7 +369,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void onDensityChanged_enabled_updateDimensionsAndResetWindowMagnification() {
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
Float.NaN);
|
||||
Mockito.reset(mWindowManager);
|
||||
Mockito.reset(mMirrorWindowControl);
|
||||
@@ -398,7 +398,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void initializeA11yNode_enabled_expectedValues() {
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(2.5f, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(2.5f, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
final View mirrorView = mWindowManager.getAttachedView();
|
||||
@@ -422,7 +422,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
public void performA11yActions_visible_expectedResults() {
|
||||
final int displayId = mContext.getDisplayId();
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(2.5f, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(2.5f, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
|
||||
@@ -449,7 +449,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
public void performA11yActions_visible_notifyAccessibilityActionPerformed() {
|
||||
final int displayId = mContext.getDisplayId();
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(2.5f, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(2.5f, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
|
||||
@@ -462,7 +462,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void enableWindowMagnification_hasA11yWindowTitle() {
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
|
||||
@@ -473,12 +473,12 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void enableWindowMagnificationWithScaleLessThanOne_enabled_disabled() {
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(0.9f, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(0.9f, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
|
||||
@@ -489,7 +489,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
public void onLocaleChanged_enabled_updateA11yWindowTitle() {
|
||||
final String newA11yWindowTitle = "new a11y window title";
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
final TestableResources testableResources = getContext().getOrCreateTestableResources();
|
||||
@@ -506,7 +506,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void onSingleTap_enabled_scaleIsChanged() {
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
|
||||
@@ -530,7 +530,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
|
||||
final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
|
||||
setSystemGestureInsets();
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
|
||||
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
|
||||
Float.NaN);
|
||||
});
|
||||
|
||||
|
||||
@@ -59,15 +59,19 @@ class WindowMagnificationConnectionWrapper {
|
||||
}
|
||||
|
||||
boolean enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
|
||||
float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
|
||||
@Nullable MagnificationAnimationCallback callback) {
|
||||
if (mTrace.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) {
|
||||
mTrace.logTrace(TAG + ".enableWindowMagnification",
|
||||
FLAGS_WINDOW_MAGNIFICATION_CONNECTION,
|
||||
"displayId=" + displayId + ";scale=" + scale + ";centerX=" + centerX
|
||||
+ ";centerY=" + centerY + ";callback=" + callback);
|
||||
+ ";centerY=" + centerY + ";magnificationFrameOffsetRatioX="
|
||||
+ magnificationFrameOffsetRatioX + ";magnificationFrameOffsetRatioY="
|
||||
+ magnificationFrameOffsetRatioY + ";callback=" + callback);
|
||||
}
|
||||
try {
|
||||
mConnection.enableWindowMagnification(displayId, scale, centerX, centerY,
|
||||
magnificationFrameOffsetRatioX, magnificationFrameOffsetRatioY,
|
||||
transformToRemoteCallback(callback, mTrace));
|
||||
} catch (RemoteException e) {
|
||||
if (DBG) {
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.server.accessibility.magnification;
|
||||
|
||||
import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
|
||||
import static android.view.MotionEvent.ACTION_CANCEL;
|
||||
import static android.view.MotionEvent.ACTION_MOVE;
|
||||
import static android.view.MotionEvent.ACTION_UP;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
@@ -78,6 +79,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
|
||||
final DetectingState mDetectingState;
|
||||
@VisibleForTesting
|
||||
final PanningScalingGestureState mObservePanningScalingState;
|
||||
@VisibleForTesting
|
||||
final ViewportDraggingState mViewportDraggingState;
|
||||
|
||||
@VisibleForTesting
|
||||
State mCurrentState;
|
||||
@@ -105,6 +108,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
|
||||
policyFlags));
|
||||
mDelegatingState = new DelegatingState(mMotionEventDispatcherDelegate);
|
||||
mDetectingState = new DetectingState(context, mDetectTripleTap);
|
||||
mViewportDraggingState = new ViewportDraggingState();
|
||||
mObservePanningScalingState = new PanningScalingGestureState(
|
||||
new PanningScalingHandler(context, MAX_SCALE, MIN_SCALE, true,
|
||||
new PanningScalingHandler.MagnificationDelegate() {
|
||||
@@ -158,7 +162,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
|
||||
public void handleShortcutTriggered() {
|
||||
final Point screenSize = mTempPoint;
|
||||
getScreenSize(mTempPoint);
|
||||
toggleMagnification(screenSize.x / 2.0f, screenSize.y / 2.0f);
|
||||
toggleMagnification(screenSize.x / 2.0f, screenSize.y / 2.0f,
|
||||
WindowMagnificationManager.WINDOW_POSITION_AT_CENTER);
|
||||
}
|
||||
|
||||
private void getScreenSize(Point outSize) {
|
||||
@@ -171,14 +176,17 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
|
||||
return Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
|
||||
}
|
||||
|
||||
private void enableWindowMagnifier(float centerX, float centerY) {
|
||||
private void enableWindowMagnifier(float centerX, float centerY,
|
||||
@WindowMagnificationManager.WindowPosition int windowPosition) {
|
||||
if (DEBUG_ALL) {
|
||||
Slog.i(mLogTag, "enableWindowMagnifier :" + centerX + ", " + centerY);
|
||||
Slog.i(mLogTag, "enableWindowMagnifier :"
|
||||
+ centerX + ", " + centerY + ", " + windowPosition);
|
||||
}
|
||||
|
||||
final float scale = MathUtils.constrain(
|
||||
mWindowMagnificationMgr.getPersistedScale(mDisplayId), MIN_SCALE, MAX_SCALE);
|
||||
mWindowMagnificationMgr.enableWindowMagnification(mDisplayId, scale, centerX, centerY);
|
||||
mWindowMagnificationMgr.enableWindowMagnification(mDisplayId, scale, centerX, centerY,
|
||||
windowPosition);
|
||||
}
|
||||
|
||||
private void disableWindowMagnifier() {
|
||||
@@ -188,11 +196,12 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
|
||||
mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, false);
|
||||
}
|
||||
|
||||
private void toggleMagnification(float centerX, float centerY) {
|
||||
private void toggleMagnification(float centerX, float centerY,
|
||||
@WindowMagnificationManager.WindowPosition int windowPosition) {
|
||||
if (mWindowMagnificationMgr.isWindowMagnifierEnabled(mDisplayId)) {
|
||||
disableWindowMagnifier();
|
||||
} else {
|
||||
enableWindowMagnifier(centerX, centerY);
|
||||
enableWindowMagnifier(centerX, centerY, windowPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +209,17 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
|
||||
if (DEBUG_DETECTING) {
|
||||
Slog.i(mLogTag, "onTripleTap()");
|
||||
}
|
||||
toggleMagnification(up.getX(), up.getY());
|
||||
toggleMagnification(up.getX(), up.getY(),
|
||||
WindowMagnificationManager.WINDOW_POSITION_AT_CENTER);
|
||||
}
|
||||
|
||||
private void onTripleTapAndHold(MotionEvent up) {
|
||||
if (DEBUG_DETECTING) {
|
||||
Slog.i(mLogTag, "onTripleTapAndHold()");
|
||||
}
|
||||
enableWindowMagnifier(up.getX(), up.getY(),
|
||||
WindowMagnificationManager.WINDOW_POSITION_AT_TOP_LEFT);
|
||||
transitionTo(mViewportDraggingState);
|
||||
}
|
||||
|
||||
void resetToDetectState() {
|
||||
@@ -319,6 +338,65 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This class handles motion events when the event dispatcher has
|
||||
* determined that the user is performing a single-finger drag of the
|
||||
* magnification viewport.
|
||||
*
|
||||
* Leaving this state until receiving {@link MotionEvent#ACTION_UP}
|
||||
* or {@link MotionEvent#ACTION_CANCEL}.
|
||||
*/
|
||||
final class ViewportDraggingState implements State {
|
||||
|
||||
private float mLastX = Float.NaN;
|
||||
private float mLastY = Float.NaN;
|
||||
|
||||
@Override
|
||||
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
|
||||
final int action = event.getActionMasked();
|
||||
switch (action) {
|
||||
case ACTION_MOVE: {
|
||||
if (!Float.isNaN(mLastX) && !Float.isNaN(mLastY)) {
|
||||
float offsetX = event.getX() - mLastX;
|
||||
float offsetY = event.getY() - mLastY;
|
||||
mWindowMagnificationMgr.moveWindowMagnification(mDisplayId, offsetX,
|
||||
offsetY);
|
||||
}
|
||||
mLastX = event.getX();
|
||||
mLastY = event.getY();
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_UP:
|
||||
case ACTION_CANCEL: {
|
||||
mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true);
|
||||
transitionTo(mDetectingState);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
mLastX = Float.NaN;
|
||||
mLastY = Float.NaN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExit() {
|
||||
clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ViewportDraggingState{"
|
||||
+ "mLastX=" + mLastX
|
||||
+ ",mLastY=" + mLastY
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class handles motion events in a duration to determine if the user is going to
|
||||
* manipulate the window magnifier or want to interact with current UI. The rule of leaving
|
||||
@@ -405,6 +483,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
|
||||
transitionTo(mObservePanningScalingState);
|
||||
} else if (gestureId == MagnificationGestureMatcher.GESTURE_TRIPLE_TAP) {
|
||||
onTripleTap(motionEvent);
|
||||
} else if (gestureId == MagnificationGestureMatcher.GESTURE_TRIPLE_TAP_AND_HOLD) {
|
||||
onTripleTapAndHold(motionEvent);
|
||||
} else {
|
||||
mMotionEventDispatcherDelegate.sendDelayedMotionEvents(delayedEventQueue,
|
||||
lastDownEventTime);
|
||||
@@ -439,6 +519,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
|
||||
return "WindowMagnificationGestureHandler{"
|
||||
+ "mDetectingState=" + mDetectingState
|
||||
+ ", mDelegatingState=" + mDelegatingState
|
||||
+ ", mViewportDraggingState=" + mViewportDraggingState
|
||||
+ ", mMagnifiedInteractionState=" + mObservePanningScalingState
|
||||
+ ", mCurrentState=" + State.nameOf(mCurrentState)
|
||||
+ ", mPreviousState=" + State.nameOf(mPreviousState)
|
||||
|
||||
@@ -20,12 +20,14 @@ import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNI
|
||||
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK;
|
||||
import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.os.Binder;
|
||||
@@ -44,6 +46,9 @@ import com.android.server.LocalServices;
|
||||
import com.android.server.accessibility.AccessibilityTraceManager;
|
||||
import com.android.server.statusbar.StatusBarManagerInternal;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* A class to manipulate window magnification through {@link WindowMagnificationConnectionWrapper}
|
||||
* create by {@link #setConnection(IWindowMagnificationConnection)}. To set the connection with
|
||||
@@ -58,6 +63,25 @@ public class WindowMagnificationManager implements
|
||||
|
||||
private static final String TAG = "WindowMagnificationMgr";
|
||||
|
||||
/**
|
||||
* Indicate that the magnification window is at the magnification center.
|
||||
*/
|
||||
public static final int WINDOW_POSITION_AT_CENTER = 0;
|
||||
|
||||
/**
|
||||
* Indicate that the magnification window is at the top-left side of the magnification
|
||||
* center. The offset is equal to a half of MirrorSurfaceView. So, the bottom-right corner
|
||||
* of the window is at the magnification center.
|
||||
*/
|
||||
public static final int WINDOW_POSITION_AT_TOP_LEFT = 1;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(prefix = { "WINDOW_POSITION_AT_" }, value = {
|
||||
WINDOW_POSITION_AT_CENTER,
|
||||
WINDOW_POSITION_AT_TOP_LEFT
|
||||
})
|
||||
public @interface WindowPosition {}
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final Context mContext;
|
||||
@VisibleForTesting
|
||||
@@ -281,20 +305,60 @@ public class WindowMagnificationManager implements
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables window magnification with specified center and scale on the specified display and
|
||||
* Enables window magnification with specified center and scale on the given display and
|
||||
* animating the transition.
|
||||
*
|
||||
* @param displayId The logical display id.
|
||||
* @param scale The target scale, must be >= 1.
|
||||
* @param centerX The screen-relative X coordinate around which to center,
|
||||
* @param centerX The screen-relative X coordinate around which to center for magnification,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
* @param centerY The screen-relative Y coordinate around which to center,
|
||||
* @param centerY The screen-relative Y coordinate around which to center for magnification,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
* @param animationCallback Called when the animation result is valid.
|
||||
* @return {@code true} if the magnification is enabled successfully.
|
||||
*/
|
||||
public boolean enableWindowMagnification(int displayId, float scale, float centerX,
|
||||
float centerY, @Nullable MagnificationAnimationCallback animationCallback) {
|
||||
return enableWindowMagnification(displayId, scale, centerX, centerY, animationCallback,
|
||||
WINDOW_POSITION_AT_CENTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables window magnification with specified center and scale on the given display and
|
||||
* animating the transition.
|
||||
*
|
||||
* @param displayId The logical display id.
|
||||
* @param scale The target scale, must be >= 1.
|
||||
* @param centerX The screen-relative X coordinate around which to center for magnification,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
* @param centerY The screen-relative Y coordinate around which to center for magnification,
|
||||
* or {@link Float#NaN} to leave unchanged.
|
||||
* @param windowPosition Indicate the offset between window position and (centerX, centerY).
|
||||
* @return {@code true} if the magnification is enabled successfully.
|
||||
*/
|
||||
public boolean enableWindowMagnification(int displayId, float scale, float centerX,
|
||||
float centerY, @WindowPosition int windowPosition) {
|
||||
return enableWindowMagnification(displayId, scale, centerX, centerY,
|
||||
STUB_ANIMATION_CALLBACK, windowPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables window magnification with specified center and scale on the given display and
|
||||
* animating the transition.
|
||||
*
|
||||
* @param displayId The logical display id.
|
||||
* @param scale The target scale, must be >= 1.
|
||||
* @param centerX The screen-relative X coordinate around which to center for
|
||||
* magnification, or {@link Float#NaN} to leave unchanged.
|
||||
* @param centerY The screen-relative Y coordinate around which to center for
|
||||
* magnification, or {@link Float#NaN} to leave unchanged.
|
||||
* @param animationCallback Called when the animation result is valid.
|
||||
* @param windowPosition Indicate the offset between window position and (centerX, centerY).
|
||||
* @return {@code true} if the magnification is enabled successfully.
|
||||
*/
|
||||
public boolean enableWindowMagnification(int displayId, float scale, float centerX,
|
||||
float centerY, @Nullable MagnificationAnimationCallback animationCallback,
|
||||
@WindowPosition int windowPosition) {
|
||||
final boolean enabled;
|
||||
boolean previousEnabled;
|
||||
synchronized (mLock) {
|
||||
@@ -307,7 +371,7 @@ public class WindowMagnificationManager implements
|
||||
}
|
||||
previousEnabled = magnifier.mEnabled;
|
||||
enabled = magnifier.enableWindowMagnificationInternal(scale, centerX, centerY,
|
||||
animationCallback);
|
||||
animationCallback, windowPosition);
|
||||
}
|
||||
|
||||
if (enabled && !previousEnabled) {
|
||||
@@ -662,6 +726,8 @@ public class WindowMagnificationManager implements
|
||||
// The magnified bounds on the screen.
|
||||
private final Rect mSourceBounds = new Rect();
|
||||
|
||||
private PointF mMagnificationFrameOffsetRatio = new PointF(0f, 0f);
|
||||
|
||||
WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager) {
|
||||
mDisplayId = displayId;
|
||||
mWindowMagnificationManager = windowMagnificationManager;
|
||||
@@ -669,14 +735,17 @@ public class WindowMagnificationManager implements
|
||||
|
||||
@GuardedBy("mLock")
|
||||
boolean enableWindowMagnificationInternal(float scale, float centerX, float centerY,
|
||||
@Nullable MagnificationAnimationCallback animationCallback) {
|
||||
@Nullable MagnificationAnimationCallback animationCallback,
|
||||
@WindowPosition int windowPosition) {
|
||||
// Handle defaults. The scale may be NAN when just updating magnification center.
|
||||
if (Float.isNaN(scale)) {
|
||||
scale = getScale();
|
||||
}
|
||||
final float normScale = MagnificationScaleProvider.constrainScale(scale);
|
||||
setMagnificationFrameOffsetRatioByWindowPosition(windowPosition);
|
||||
if (mWindowMagnificationManager.enableWindowMagnificationInternal(mDisplayId, normScale,
|
||||
centerX, centerY, animationCallback)) {
|
||||
centerX, centerY, mMagnificationFrameOffsetRatio.x,
|
||||
mMagnificationFrameOffsetRatio.y, animationCallback)) {
|
||||
mScale = normScale;
|
||||
mEnabled = true;
|
||||
|
||||
@@ -685,6 +754,19 @@ public class WindowMagnificationManager implements
|
||||
return false;
|
||||
}
|
||||
|
||||
void setMagnificationFrameOffsetRatioByWindowPosition(@WindowPosition int windowPosition) {
|
||||
switch (windowPosition) {
|
||||
case WINDOW_POSITION_AT_CENTER: {
|
||||
mMagnificationFrameOffsetRatio.set(0f, 0f);
|
||||
}
|
||||
break;
|
||||
case WINDOW_POSITION_AT_TOP_LEFT: {
|
||||
mMagnificationFrameOffsetRatio.set(-1f, -1f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
boolean disableWindowMagnificationInternal(
|
||||
@Nullable MagnificationAnimationCallback animationResultCallback) {
|
||||
@@ -768,9 +850,15 @@ public class WindowMagnificationManager implements
|
||||
}
|
||||
|
||||
private boolean enableWindowMagnificationInternal(int displayId, float scale, float centerX,
|
||||
float centerY, MagnificationAnimationCallback animationCallback) {
|
||||
return mConnectionWrapper != null && mConnectionWrapper.enableWindowMagnification(
|
||||
displayId, scale, centerX, centerY, animationCallback);
|
||||
float centerY, float magnificationFrameOffsetRatioX,
|
||||
float magnificationFrameOffsetRatioY,
|
||||
MagnificationAnimationCallback animationCallback) {
|
||||
synchronized (mLock) {
|
||||
return mConnectionWrapper != null && mConnectionWrapper.enableWindowMagnification(
|
||||
displayId, scale, centerX, centerY,
|
||||
magnificationFrameOffsetRatioX, magnificationFrameOffsetRatioY,
|
||||
animationCallback);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean setScaleInternal(int displayId, float scale) {
|
||||
|
||||
@@ -155,7 +155,7 @@ public class MagnificationControllerTest {
|
||||
verify(mScreenMagnificationController, never()).reset(anyInt(),
|
||||
any(MagnificationAnimationCallback.class));
|
||||
verify(mMockConnection.getConnection(), never()).enableWindowMagnification(anyInt(),
|
||||
anyFloat(), anyFloat(), anyFloat(),
|
||||
anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(),
|
||||
nullable(IRemoteMagnificationAnimationCallback.class));
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ class MockWindowMagnificationConnection {
|
||||
final float scale = invocation.getArgument(1);
|
||||
mScale = Float.isNaN(scale) ? mScale : scale;
|
||||
computeMirrorWindowFrame(invocation.getArgument(2), invocation.getArgument(3));
|
||||
setAnimationCallback(invocation.getArgument(4));
|
||||
setAnimationCallback(invocation.getArgument(6));
|
||||
computeSourceBounds();
|
||||
mHasPendingCallback = true;
|
||||
if (!mSuspendCallback) {
|
||||
@@ -101,7 +101,7 @@ class MockWindowMagnificationConnection {
|
||||
}
|
||||
return null;
|
||||
}).when(mConnection).enableWindowMagnification(anyInt(), anyFloat(), anyFloat(), anyFloat(),
|
||||
nullable(IRemoteMagnificationAnimationCallback.class));
|
||||
anyFloat(), anyFloat(), nullable(IRemoteMagnificationAnimationCallback.class));
|
||||
}
|
||||
|
||||
private void stubDisableWindowMagnification() throws RemoteException {
|
||||
|
||||
@@ -67,7 +67,7 @@ public class WindowMagnificationConnectionWrapperTest {
|
||||
@Test
|
||||
public void enableWindowMagnification() throws RemoteException {
|
||||
mConnectionWrapper.enableWindowMagnification(TEST_DISPLAY, 2, 100f, 200f,
|
||||
mAnimationCallback);
|
||||
0f, 0f, mAnimationCallback);
|
||||
|
||||
verify(mAnimationCallback).onResult(true);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import static org.mockito.Mockito.mock;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.testing.TestableContext;
|
||||
import android.util.DebugUtils;
|
||||
import android.view.InputDevice;
|
||||
@@ -58,10 +59,11 @@ public class WindowMagnificationGestureHandlerTest {
|
||||
public static final int STATE_SHOW_MAGNIFIER_SHORTCUT = 2;
|
||||
public static final int STATE_TWO_FINGERS_DOWN = 3;
|
||||
public static final int STATE_SHOW_MAGNIFIER_TRIPLE_TAP = 4;
|
||||
public static final int STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD = 5;
|
||||
//TODO: Test it after can injecting Handler to GestureMatcher is available.
|
||||
|
||||
public static final int FIRST_STATE = STATE_IDLE;
|
||||
public static final int LAST_STATE = STATE_SHOW_MAGNIFIER_TRIPLE_TAP;
|
||||
public static final int LAST_STATE = STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD;
|
||||
|
||||
// Co-prime x and y, to potentially catch x-y-swapped errors
|
||||
public static final float DEFAULT_TAP_X = 301;
|
||||
@@ -178,6 +180,12 @@ public class WindowMagnificationGestureHandlerTest {
|
||||
== mWindowMagnificationGestureHandler.mDetectingState, state);
|
||||
}
|
||||
break;
|
||||
case STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD: {
|
||||
check(isWindowMagnifierEnabled(DISPLAY_0), state);
|
||||
check(mWindowMagnificationGestureHandler.mCurrentState
|
||||
== mWindowMagnificationGestureHandler.mViewportDraggingState, state);
|
||||
}
|
||||
break;
|
||||
case STATE_TWO_FINGERS_DOWN: {
|
||||
check(isWindowMagnifierEnabled(DISPLAY_0), state);
|
||||
check(mWindowMagnificationGestureHandler.mCurrentState
|
||||
@@ -229,6 +237,13 @@ public class WindowMagnificationGestureHandlerTest {
|
||||
tap();
|
||||
}
|
||||
break;
|
||||
case STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD: {
|
||||
// Perform triple tap and hold gesture
|
||||
tap();
|
||||
tap();
|
||||
tapAndHold();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal state: " + state);
|
||||
}
|
||||
@@ -262,6 +277,10 @@ public class WindowMagnificationGestureHandlerTest {
|
||||
tap();
|
||||
}
|
||||
break;
|
||||
case STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD: {
|
||||
send(upEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal state: " + state);
|
||||
}
|
||||
@@ -308,6 +327,11 @@ public class WindowMagnificationGestureHandlerTest {
|
||||
send(upEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
|
||||
}
|
||||
|
||||
private void tapAndHold() {
|
||||
send(downEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
|
||||
SystemClock.sleep(ViewConfiguration.getLongPressTimeout() + 100);
|
||||
}
|
||||
|
||||
private String stateDump() {
|
||||
return "\nCurrent state dump:\n" + mWindowMagnificationGestureHandler.mCurrentState;
|
||||
}
|
||||
|
||||
@@ -143,8 +143,7 @@ public class WindowMagnificationManagerTest {
|
||||
* new connection.
|
||||
*/
|
||||
@Test
|
||||
public void
|
||||
setSecondConnectionAndFormerConnectionBinderDead_hasWrapperAndNotCallUnlinkToDeath()
|
||||
public void setSecondConnectionAndFormerConnectionBinderDead_hasWrapperAndNotCallUnlinkToDeath()
|
||||
throws RemoteException {
|
||||
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
|
||||
MockWindowMagnificationConnection secondConnection =
|
||||
@@ -177,7 +176,7 @@ public class WindowMagnificationManagerTest {
|
||||
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, 200f, 300f);
|
||||
|
||||
verify(mMockConnection.getConnection()).enableWindowMagnification(eq(TEST_DISPLAY), eq(2f),
|
||||
eq(200f), eq(300f), notNull());
|
||||
eq(200f), eq(300f), eq(0f), eq(0f), notNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -189,7 +188,8 @@ public class WindowMagnificationManagerTest {
|
||||
mAnimationCallback);
|
||||
|
||||
verify(mMockConnection.getConnection()).enableWindowMagnification(eq(TEST_DISPLAY), eq(2f),
|
||||
eq(200f), eq(300f), any(IRemoteMagnificationAnimationCallback.class));
|
||||
eq(200f), eq(300f), eq(0f), eq(0f),
|
||||
any(IRemoteMagnificationAnimationCallback.class));
|
||||
verify(mAnimationCallback).onResult(true);
|
||||
}
|
||||
|
||||
@@ -410,6 +410,34 @@ public class WindowMagnificationManagerTest {
|
||||
assertEquals(mWindowMagnificationManager.getCenterY(TEST_DISPLAY), 200f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void centerGetter_enabledOnTestDisplayWindowAtCenter_expectedValues()
|
||||
throws RemoteException {
|
||||
mWindowMagnificationManager.requestConnection(true);
|
||||
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f,
|
||||
100f, 200f, WindowMagnificationManager.WINDOW_POSITION_AT_CENTER);
|
||||
|
||||
assertEquals(mWindowMagnificationManager.getCenterX(TEST_DISPLAY), 100f);
|
||||
assertEquals(mWindowMagnificationManager.getCenterY(TEST_DISPLAY), 200f);
|
||||
|
||||
verify(mMockConnection.getConnection()).enableWindowMagnification(eq(TEST_DISPLAY), eq(3f),
|
||||
eq(100f), eq(200f), eq(0f), eq(0f), notNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void centerGetter_enabledOnTestDisplayWindowAtLeftTop_expectedValues()
|
||||
throws RemoteException {
|
||||
mWindowMagnificationManager.requestConnection(true);
|
||||
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f,
|
||||
100f, 200f, WindowMagnificationManager.WINDOW_POSITION_AT_TOP_LEFT);
|
||||
|
||||
assertEquals(mWindowMagnificationManager.getCenterX(TEST_DISPLAY), 100f);
|
||||
assertEquals(mWindowMagnificationManager.getCenterY(TEST_DISPLAY), 200f);
|
||||
|
||||
verify(mMockConnection.getConnection()).enableWindowMagnification(eq(TEST_DISPLAY), eq(3f),
|
||||
eq(100f), eq(200f), eq(-1f), eq(-1f), notNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDisplayRemoved_enabledOnTestDisplay_disabled() {
|
||||
mWindowMagnificationManager.requestConnection(true);
|
||||
|
||||
Reference in New Issue
Block a user