diff --git a/core/api/current.txt b/core/api/current.txt index 1c32c93ae365f..565928dfa9870 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -3143,6 +3143,7 @@ package android.accessibilityservice { public static interface AccessibilityService.MagnificationController.OnMagnificationChangedListener { method public void onMagnificationChanged(@NonNull android.accessibilityservice.AccessibilityService.MagnificationController, @NonNull android.graphics.Region, float, float, float); + method public default void onMagnificationChanged(@NonNull android.accessibilityservice.AccessibilityService.MagnificationController, @NonNull android.graphics.Region, @NonNull android.accessibilityservice.MagnificationConfig); } public static final class AccessibilityService.ScreenshotResult { diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 9a5586747d0eb..d3e7c159b73a0 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -588,7 +588,7 @@ public abstract class AccessibilityService extends Service { boolean onKeyEvent(KeyEvent event); /** Magnification changed callbacks for different displays */ void onMagnificationChanged(int displayId, @NonNull Region region, - float scale, float centerX, float centerY); + MagnificationConfig config); /** Callbacks for receiving motion events. */ void onMotionEvent(MotionEvent event); /** Callback for tuch state changes. */ @@ -1183,14 +1183,14 @@ public abstract class AccessibilityService extends Service { } } - private void onMagnificationChanged(int displayId, @NonNull Region region, float scale, - float centerX, float centerY) { + private void onMagnificationChanged(int displayId, @NonNull Region region, + MagnificationConfig config) { MagnificationController controller; synchronized (mLock) { controller = mMagnificationControllers.get(displayId); } if (controller != null) { - controller.dispatchMagnificationChanged(region, scale, centerX, centerY); + controller.dispatchMagnificationChanged(region, config); } } @@ -1328,8 +1328,8 @@ public abstract class AccessibilityService extends Service { * Dispatches magnification changes to any registered listeners. This * should be called on the service's main thread. */ - void dispatchMagnificationChanged(final @NonNull Region region, final float scale, - final float centerX, final float centerY) { + void dispatchMagnificationChanged(final @NonNull Region region, + final MagnificationConfig config) { final ArrayMap entries; synchronized (mLock) { if (mListeners == null || mListeners.isEmpty()) { @@ -1348,16 +1348,13 @@ public abstract class AccessibilityService extends Service { final OnMagnificationChangedListener listener = entries.keyAt(i); final Handler handler = entries.valueAt(i); if (handler != null) { - handler.post(new Runnable() { - @Override - public void run() { - listener.onMagnificationChanged(MagnificationController.this, - region, scale, centerX, centerY); - } + handler.post(() -> { + listener.onMagnificationChanged(MagnificationController.this, + region, config); }); } else { // We're already on the main thread, just run the listener. - listener.onMagnificationChanged(this, region, scale, centerX, centerY); + listener.onMagnificationChanged(this, region, config); } } } @@ -1665,6 +1662,10 @@ public abstract class AccessibilityService extends Service { public interface OnMagnificationChangedListener { /** * Called when the magnified region, scale, or center changes. + *

+ * Note: This legacy callback notifies only full-screen + * magnification change. + *

* * @param controller the magnification controller * @param region the magnification region @@ -1676,6 +1677,38 @@ public abstract class AccessibilityService extends Service { */ void onMagnificationChanged(@NonNull MagnificationController controller, @NonNull Region region, float scale, float centerX, float centerY); + + /** + * Called when the magnified region, mode, scale, or center changes of + * all magnification modes. + *

+ * Note: This method can be overridden to listen to the + * magnification changes of all magnification modes then the legacy callback + * would not receive the notifications. + * Skipping calling super when overriding this method results in + * {@link #onMagnificationChanged(MagnificationController, Region, float, float, float)} + * not getting called. + *

+ * + * @param controller the magnification controller + * @param region the magnification region + * If the config mode is + * {@link MagnificationConfig#MAGNIFICATION_MODE_FULLSCREEN}, + * it is the region of the screen currently active for magnification. + * that is the same region as {@link #getMagnificationRegion()}. + * If the config mode is + * {@link MagnificationConfig#MAGNIFICATION_MODE_WINDOW}, + * it is the region of screen projected on the magnification window. + * @param config The magnification config. That has the controlling magnification + * mode, the new scale and the new screen-relative center position + */ + default void onMagnificationChanged(@NonNull MagnificationController controller, + @NonNull Region region, @NonNull MagnificationConfig config) { + if (config.getMode() == MAGNIFICATION_MODE_FULLSCREEN) { + onMagnificationChanged(controller, region, + config.getScale(), config.getCenterX(), config.getCenterY()); + } + } } } @@ -2449,9 +2482,8 @@ public abstract class AccessibilityService extends Service { @Override public void onMagnificationChanged(int displayId, @NonNull Region region, - float scale, float centerX, float centerY) { - AccessibilityService.this.onMagnificationChanged(displayId, region, scale, - centerX, centerY); + MagnificationConfig config) { + AccessibilityService.this.onMagnificationChanged(displayId, region, config); } @Override @@ -2575,12 +2607,10 @@ public abstract class AccessibilityService extends Service { /** Magnification changed callbacks for different displays */ public void onMagnificationChanged(int displayId, @NonNull Region region, - float scale, float centerX, float centerY) { + MagnificationConfig config) { final SomeArgs args = SomeArgs.obtain(); args.arg1 = region; - args.arg2 = scale; - args.arg3 = centerX; - args.arg4 = centerY; + args.arg2 = config; args.argi1 = displayId; final Message message = mCaller.obtainMessageO(DO_ON_MAGNIFICATION_CHANGED, args); @@ -2739,13 +2769,10 @@ public abstract class AccessibilityService extends Service { if (mConnectionId != AccessibilityInteractionClient.NO_ID) { final SomeArgs args = (SomeArgs) message.obj; final Region region = (Region) args.arg1; - final float scale = (float) args.arg2; - final float centerX = (float) args.arg3; - final float centerY = (float) args.arg4; + final MagnificationConfig config = (MagnificationConfig) args.arg2; final int displayId = args.argi1; args.recycle(); - mCallback.onMagnificationChanged(displayId, region, scale, - centerX, centerY); + mCallback.onMagnificationChanged(displayId, region, config); } return; } diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl index 651c50f475c68..375383d5d8588 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl @@ -21,6 +21,7 @@ import android.graphics.Region; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityWindowInfo; import android.accessibilityservice.AccessibilityGestureEvent; +import android.accessibilityservice.MagnificationConfig; import android.view.KeyEvent; import android.view.MotionEvent; @@ -43,7 +44,7 @@ import android.view.MotionEvent; void onKeyEvent(in KeyEvent event, int sequence); - void onMagnificationChanged(int displayId, in Region region, float scale, float centerX, float centerY); + void onMagnificationChanged(int displayId, in Region region, in MagnificationConfig config); void onMotionEvent(in MotionEvent event); diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 58ded716cf40d..00903a8808340 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -22,6 +22,7 @@ import android.accessibilityservice.AccessibilityService.IAccessibilityServiceCl import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.IAccessibilityServiceClient; import android.accessibilityservice.IAccessibilityServiceConnection; +import android.accessibilityservice.MagnificationConfig; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1581,7 +1582,7 @@ public final class UiAutomation { @Override public void onMagnificationChanged(int displayId, @NonNull Region region, - float scale, float centerX, float centerY) { + MagnificationConfig config) { /* do nothing */ } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index b064ba904120f..41b3e31dba9ac 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -252,7 +252,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold mMagnificationFrame.height()); mTransaction.setGeometry(mMirrorSurface, mSourceBounds, mTmpRect, Surface.ROTATION_0).apply(); - mWindowMagnifierCallback.onSourceBoundsChanged(mDisplayId, mSourceBounds); + + // Notify source bounds change when the magnifier is not animating. + if (!mAnimationController.isAnimating()) { + mWindowMagnifierCallback.onSourceBoundsChanged(mDisplayId, + mSourceBounds); + } } }; mUpdateStateDescriptionRunnable = () -> { @@ -596,7 +601,6 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold private void modifyWindowMagnification(SurfaceControl.Transaction t) { mSfVsyncFrameProvider.postFrameCallback(mMirrorViewGeometryVsyncCallback); updateMirrorViewLayout(); - } /** @@ -800,7 +804,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold * 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, + public void enableWindowMagnification(float scale, float centerX, float centerY, float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY, @Nullable IRemoteMagnificationAnimationCallback animationCallback) { mAnimationController.enableWindowMagnification(scale, centerX, centerY, diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java index 8fdcaddc93fbd..5ad651728c66a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java @@ -34,6 +34,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.spy; @@ -60,6 +61,7 @@ import android.view.View; import android.view.WindowInsets; import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.IRemoteMagnificationAnimationCallback; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; @@ -75,6 +77,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -89,8 +92,6 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { @Mock private Handler mHandler; @Mock - private WindowMagnificationAnimationController mWindowMagnificationAnimationController; - @Mock private SfVsyncFrameCallbackProvider mSfVsyncFrameProvider; @Mock private MirrorWindowControl mMirrorWindowControl; @@ -101,6 +102,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { private TestableWindowManager mWindowManager; private SysUiState mSysUiState = new SysUiState(); private Resources mResources; + private WindowMagnificationAnimationController mWindowMagnificationAnimationController; private WindowMagnificationController mWindowMagnificationController; private Instrumentation mInstrumentation; @@ -125,10 +127,11 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { return null; }).when(mHandler).post( any(Runnable.class)); - mSysUiState.addCallback(Mockito.mock(SysUiState.SysUiStateCallback.class)); mResources = getContext().getOrCreateTestableResources().getResources(); + mWindowMagnificationAnimationController = new WindowMagnificationAnimationController( + mContext); mWindowMagnificationController = new WindowMagnificationController(mContext, mHandler, mWindowMagnificationAnimationController, mSfVsyncFrameProvider, mMirrorWindowControl, mTransaction, mWindowMagnifierCallback, mSysUiState); @@ -156,6 +159,52 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { eq(mContext.getDisplayId()), any(Rect.class)); } + @Test + public void enableWindowMagnification_notifySourceBoundsChanged() { + mInstrumentation.runOnMainSync(() -> { + mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN, + Float.NaN, /* magnificationFrameOffsetRatioX= */ 0, + /* magnificationFrameOffsetRatioY= */ 0, null); + }); + + // Waits for the surface created + verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS)).onSourceBoundsChanged( + (eq(mContext.getDisplayId())), any()); + } + + @Test + public void enableWindowMagnification_withAnimation_schedulesFrame() { + mInstrumentation.runOnMainSync(() -> { + mWindowMagnificationController.enableWindowMagnification(2.0f, 10, + 10, /* magnificationFrameOffsetRatioX= */ 0, + /* magnificationFrameOffsetRatioY= */ 0, + Mockito.mock(IRemoteMagnificationAnimationCallback.class)); + }); + + verify(mSfVsyncFrameProvider, + timeout(LAYOUT_CHANGE_TIMEOUT_MS).atLeast(2)).postFrameCallback(any()); + } + + @Test + public void moveWindowMagnifier_enabled_notifySourceBoundsChanged() { + mInstrumentation.runOnMainSync(() -> { + mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN, + Float.NaN, 0, 0, null); + }); + + mInstrumentation.runOnMainSync(() -> { + mWindowMagnificationController.moveWindowMagnifier(10, 10); + }); + + final ArgumentCaptor sourceBoundsCaptor = ArgumentCaptor.forClass(Rect.class); + verify(mWindowMagnifierCallback, atLeast(2)).onSourceBoundsChanged( + (eq(mContext.getDisplayId())), sourceBoundsCaptor.capture()); + assertEquals(mWindowMagnificationController.getCenterX(), + sourceBoundsCaptor.getValue().exactCenterX(), 0); + assertEquals(mWindowMagnificationController.getCenterY(), + sourceBoundsCaptor.getValue().exactCenterY(), 0); + } + @Test public void enableWindowMagnification_systemGestureExclusionRectsIsSet() { mInstrumentation.runOnMainSync(() -> { diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index ad3e1d56c51bf..487eb553d58e6 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -1542,9 +1542,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, - float scale, float centerX, float centerY) { + @NonNull MagnificationConfig config) { mInvocationHandler - .notifyMagnificationChangedLocked(displayId, region, scale, centerX, centerY); + .notifyMagnificationChangedLocked(displayId, region, config); } public void notifySoftKeyboardShowModeChangedLocked(int showState) { @@ -1564,15 +1564,15 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ * state of magnification has changed. */ private void notifyMagnificationChangedInternal(int displayId, @NonNull Region region, - float scale, float centerX, float centerY) { + @NonNull MagnificationConfig config) { final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); if (listener != null) { try { if (svcClientTracingEnabled()) { logTraceSvcClient("onMagnificationChanged", displayId + ", " + region + ", " - + scale + ", " + centerX + ", " + centerY); + + config.toString()); } - listener.onMagnificationChanged(displayId, region, scale, centerX, centerY); + listener.onMagnificationChanged(displayId, region, config); } catch (RemoteException re) { Slog.e(LOG_TAG, "Error sending magnification changes to " + mService, re); } @@ -1899,11 +1899,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ case MSG_ON_MAGNIFICATION_CHANGED: { final SomeArgs args = (SomeArgs) message.obj; final Region region = (Region) args.arg1; - final float scale = (float) args.arg2; - final float centerX = (float) args.arg3; - final float centerY = (float) args.arg4; + final MagnificationConfig config = (MagnificationConfig) args.arg2; final int displayId = args.argi1; - notifyMagnificationChangedInternal(displayId, region, scale, centerX, centerY); + notifyMagnificationChangedInternal(displayId, region, config); args.recycle(); } break; @@ -1932,7 +1930,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, - float scale, float centerX, float centerY) { + @NonNull MagnificationConfig config) { synchronized (mLock) { if (mMagnificationCallbackState.get(displayId) == null) { return; @@ -1941,9 +1939,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ final SomeArgs args = SomeArgs.obtain(); args.arg1 = region; - args.arg2 = scale; - args.arg3 = centerX; - args.arg4 = centerY; + args.arg2 = config; args.argi1 = displayId; final Message msg = obtainMessage(MSG_ON_MAGNIFICATION_CHANGED, args); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index e59a3d633cfd0..7074167a88c32 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -44,6 +44,7 @@ import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.AccessibilityShortcutInfo; import android.accessibilityservice.IAccessibilityServiceClient; +import android.accessibilityservice.MagnificationConfig; import android.accessibilityservice.TouchInteractionController; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1301,18 +1302,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub * Called by the MagnificationController when the state of display * magnification changes. * - * @param displayId The logical display id. + *

+ * It can notify window magnification change if the service supports controlling all the + * magnification mode. + *

+ * + * @param displayId The logical display id * @param region the new magnified region, may be empty if * magnification is not enabled (e.g. scale is 1) - * @param scale the new scale - * @param centerX the new screen-relative center X coordinate - * @param centerY the new screen-relative center Y coordinate + * @param config The magnification config. That has magnification mode, the new scale and the + * new screen-relative center position */ public void notifyMagnificationChanged(int displayId, @NonNull Region region, - float scale, float centerX, float centerY) { + @NonNull MagnificationConfig config) { synchronized (mLock) { notifyClearAccessibilityCacheLocked(); - notifyMagnificationChangedLocked(displayId, region, scale, centerX, centerY); + notifyMagnificationChangedLocked(displayId, region, config); } } @@ -1613,11 +1618,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } private void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, - float scale, float centerX, float centerY) { + @NonNull MagnificationConfig config) { final AccessibilityUserState state = getCurrentUserStateLocked(); for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { final AccessibilityServiceConnection service = state.mBoundServices.get(i); - service.notifyMagnificationChangedLocked(displayId, region, scale, centerX, centerY); + service.notifyMagnificationChangedLocked(displayId, region, config); } } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java index 72bc8503b7a53..4d898c87f966f 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java @@ -17,10 +17,12 @@ package com.android.server.accessibility.magnification; import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL; +import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_FULLSCREEN; import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK; import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID; +import android.accessibilityservice.MagnificationConfig; import android.animation.Animator; import android.animation.ValueAnimator; import android.annotation.NonNull; @@ -363,9 +365,16 @@ public class FullScreenMagnificationController implements return mIdOfLastServiceToMagnify; } + @GuardedBy("mLock") void onMagnificationChangedLocked() { - mControllerCtx.getAms().notifyMagnificationChanged(mDisplayId, mMagnificationRegion, - getScale(), getCenterX(), getCenterY()); + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(MAGNIFICATION_MODE_FULLSCREEN) + .setScale(getScale()) + .setCenterX(getCenterX()) + .setCenterY(getCenterY()).build(); + mControllerCtx.getAms().notifyMagnificationChanged(mDisplayId, + mMagnificationRegion, + config); if (mUnregisterPending && !isMagnifying()) { unregister(mDeleteAfterUnregister); } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java index 037dc1f6795ca..342d13a0f846f 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java @@ -16,6 +16,7 @@ package com.android.server.accessibility.magnification; +import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_WINDOW; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE; @@ -379,6 +380,16 @@ public class MagnificationController implements WindowMagnificationManager.Callb mAms.changeMagnificationMode(displayId, magnificationMode); } + @Override + public void onSourceBoundsChanged(int displayId, Rect bounds) { + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(MAGNIFICATION_MODE_WINDOW) + .setScale(mScaleProvider.getScale(displayId)) + .setCenterX(bounds.exactCenterX()) + .setCenterY(bounds.exactCenterY()).build(); + mAms.notifyMagnificationChanged(displayId, new Region(bounds), config); + } + private void disableFullScreenMagnificationIfNeeded(int displayId) { final FullScreenMagnificationController fullScreenMagnificationController = getFullScreenMagnificationController(); diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java index c4a577d6e4611..bb764320d7aaf 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java @@ -138,6 +138,14 @@ public class WindowMagnificationManager implements */ void onWindowMagnificationActivationState(int displayId, boolean activated); + /** + * Called when the magnification source bounds are changed. + * + * @param displayId The logical display id. + * @param bounds The magnified source bounds on the display. + */ + void onSourceBoundsChanged(int displayId, Rect bounds); + /** * Called from {@link IWindowMagnificationConnection} to request changing the magnification * mode on the given display. @@ -689,6 +697,7 @@ public class WindowMagnificationManager implements } magnifier.onSourceBoundsChanged(sourceBounds); } + mCallback.onSourceBoundsChanged(displayId, sourceBounds); } @Override diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java index 96af61737bff0..dadc890c56e4d 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java @@ -16,6 +16,8 @@ package com.android.server.accessibility.magnification; +import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_FULLSCREEN; + import static com.android.server.accessibility.magnification.FullScreenMagnificationController.MagnificationInfoChangedCallback; import static org.junit.Assert.assertEquals; @@ -23,10 +25,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -37,6 +37,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.mockito.hamcrest.MockitoHamcrest.argThat; +import android.accessibilityservice.MagnificationConfig; import android.animation.ValueAnimator; import android.content.BroadcastReceiver; import android.content.Context; @@ -105,6 +106,8 @@ public class FullScreenMagnificationControllerTest { private final MagnificationScaleProvider mScaleProvider = mock( MagnificationScaleProvider.class); + private final ArgumentCaptor mConfigCaptor = ArgumentCaptor.forClass( + MagnificationConfig.class); ValueAnimator mMockValueAnimator; ValueAnimator.AnimatorUpdateListener mTargetAnimationListener; @@ -142,13 +145,13 @@ public class FullScreenMagnificationControllerTest { register(DISPLAY_1); register(INVALID_DISPLAY); verify(mMockContext).registerReceiver( - (BroadcastReceiver) anyObject(), (IntentFilter) anyObject()); + any(BroadcastReceiver.class), any(IntentFilter.class)); verify(mMockWindowManager).setMagnificationCallbacks( - eq(DISPLAY_0), (MagnificationCallbacks) anyObject()); + eq(DISPLAY_0), any(MagnificationCallbacks.class)); verify(mMockWindowManager).setMagnificationCallbacks( - eq(DISPLAY_1), (MagnificationCallbacks) anyObject()); + eq(DISPLAY_1), any(MagnificationCallbacks.class)); verify(mMockWindowManager).setMagnificationCallbacks( - eq(INVALID_DISPLAY), (MagnificationCallbacks) anyObject()); + eq(INVALID_DISPLAY), any(MagnificationCallbacks.class)); assertTrue(mFullScreenMagnificationController.isRegistered(DISPLAY_0)); assertTrue(mFullScreenMagnificationController.isRegistered(DISPLAY_1)); assertFalse(mFullScreenMagnificationController.isRegistered(INVALID_DISPLAY)); @@ -159,9 +162,9 @@ public class FullScreenMagnificationControllerTest { register(DISPLAY_0); register(DISPLAY_1); mFullScreenMagnificationController.unregister(DISPLAY_0); - verify(mMockContext, times(0)).unregisterReceiver((BroadcastReceiver) anyObject()); + verify(mMockContext, times(0)).unregisterReceiver(any(BroadcastReceiver.class)); mFullScreenMagnificationController.unregister(DISPLAY_1); - verify(mMockContext).unregisterReceiver((BroadcastReceiver) anyObject()); + verify(mMockContext).unregisterReceiver(any(BroadcastReceiver.class)); verify(mMockWindowManager).setMagnificationCallbacks(eq(DISPLAY_0), eq(null)); verify(mMockWindowManager).setMagnificationCallbacks(eq(DISPLAY_1), eq(null)); assertFalse(mFullScreenMagnificationController.isRegistered(DISPLAY_0)); @@ -343,6 +346,7 @@ public class FullScreenMagnificationControllerTest { MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId); float scale = 2.5f; PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER; + final MagnificationConfig config = buildConfig(scale, newCenter.x, newCenter.y); PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale); MagnificationSpec endSpec = getMagnificationSpec(scale, offsets); @@ -353,8 +357,9 @@ public class FullScreenMagnificationControllerTest { assertEquals(newCenter.x, mFullScreenMagnificationController.getCenterX(displayId), 0.5); assertEquals(newCenter.y, mFullScreenMagnificationController.getCenterY(displayId), 0.5); assertThat(getCurrentMagnificationSpec(displayId), closeTo(endSpec)); - verify(mMockAms).notifyMagnificationChanged(displayId, - INITIAL_MAGNIFICATION_REGION, scale, newCenter.x, newCenter.y); + verify(mMockAms).notifyMagnificationChanged(eq(displayId), eq(INITIAL_MAGNIFICATION_REGION), + mConfigCaptor.capture()); + assertConfigEquals(config, mConfigCaptor.getValue()); verify(mMockValueAnimator).start(); verify(mRequestObserver).onRequestMagnificationSpec(displayId, SERVICE_ID_1); @@ -494,8 +499,11 @@ public class FullScreenMagnificationControllerTest { MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId); callbacks.onMagnificationRegionChanged(OTHER_REGION); mMessageCapturingHandler.sendAllMessages(); - verify(mMockAms).notifyMagnificationChanged(displayId, OTHER_REGION, 1.0f, - OTHER_MAGNIFICATION_BOUNDS.centerX(), OTHER_MAGNIFICATION_BOUNDS.centerY()); + MagnificationConfig config = buildConfig(1.0f, OTHER_MAGNIFICATION_BOUNDS.centerX(), + OTHER_MAGNIFICATION_BOUNDS.centerY()); + verify(mMockAms).notifyMagnificationChanged(eq(displayId), eq(OTHER_REGION), + mConfigCaptor.capture()); + assertConfigEquals(config, mConfigCaptor.getValue()); } @Test @@ -650,7 +658,7 @@ public class FullScreenMagnificationControllerTest { reset(mMockAms); assertTrue(mFullScreenMagnificationController.resetIfNeeded(displayId, false)); verify(mMockAms).notifyMagnificationChanged(eq(displayId), - eq(INITIAL_MAGNIFICATION_REGION), eq(1.0f), anyFloat(), anyFloat()); + eq(INITIAL_MAGNIFICATION_REGION), any(MagnificationConfig.class)); assertFalse(mFullScreenMagnificationController.isMagnifying(displayId)); assertFalse(mFullScreenMagnificationController.resetIfNeeded(displayId, false)); } @@ -668,8 +676,8 @@ public class FullScreenMagnificationControllerTest { assertFalse(mFullScreenMagnificationController.reset(displayId, mAnimationCallback)); mMessageCapturingHandler.sendAllMessages(); - verify(mMockAms, never()).notifyMagnificationChanged(eq(displayId), - any(Region.class), anyFloat(), anyFloat(), anyFloat()); + verify(mMockAms, never()).notifyMagnificationChanged(eq(displayId), any(Region.class), + any(MagnificationConfig.class)); verify(mAnimationCallback).onResult(true); } @@ -726,7 +734,7 @@ public class FullScreenMagnificationControllerTest { ArgumentCaptor broadcastReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); verify(mMockContext).registerReceiver( - broadcastReceiverCaptor.capture(), (IntentFilter) anyObject()); + broadcastReceiverCaptor.capture(), any(IntentFilter.class)); BroadcastReceiver br = broadcastReceiverCaptor.getValue(); zoomIn2xToMiddle(DISPLAY_0); zoomIn2xToMiddle(DISPLAY_1); @@ -1031,6 +1039,7 @@ public class FullScreenMagnificationControllerTest { MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId); float scale = 2.5f; PointF firstCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER; + final MagnificationConfig config = buildConfig(scale, firstCenter.x, firstCenter.y); MagnificationSpec firstEndSpec = getMagnificationSpec( scale, computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, firstCenter, scale)); @@ -1047,8 +1056,9 @@ public class FullScreenMagnificationControllerTest { when(mMockValueAnimator.getAnimatedFraction()).thenReturn(0.0f); mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator); verify(mMockWindowManager).setMagnificationSpec(eq(displayId), eq(startSpec)); - verify(mMockAms).notifyMagnificationChanged(displayId, - INITIAL_MAGNIFICATION_REGION, scale, firstCenter.x, firstCenter.y); + verify(mMockAms).notifyMagnificationChanged(eq(displayId), eq(INITIAL_MAGNIFICATION_REGION), + mConfigCaptor.capture()); + assertConfigEquals(config, mConfigCaptor.getValue()); Mockito.reset(mMockWindowManager); // Intermediate point @@ -1062,6 +1072,7 @@ public class FullScreenMagnificationControllerTest { Mockito.reset(mMockWindowManager); PointF newCenter = INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER; + final MagnificationConfig newConfig = buildConfig(scale, newCenter.x, newCenter.y); MagnificationSpec newEndSpec = getMagnificationSpec( scale, computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale)); assertTrue(mFullScreenMagnificationController.setCenter(displayId, @@ -1070,8 +1081,9 @@ public class FullScreenMagnificationControllerTest { // Animation should have been restarted verify(mMockValueAnimator, times(2)).start(); - verify(mMockAms).notifyMagnificationChanged(displayId, - INITIAL_MAGNIFICATION_REGION, scale, newCenter.x, newCenter.y); + verify(mMockAms, times(2)).notifyMagnificationChanged(eq(displayId), + eq(INITIAL_MAGNIFICATION_REGION), mConfigCaptor.capture()); + assertConfigEquals(newConfig, mConfigCaptor.getValue()); // New starting point should be where we left off when(mMockValueAnimator.getAnimatedFraction()).thenReturn(0.0f); @@ -1155,7 +1167,7 @@ public class FullScreenMagnificationControllerTest { Region regionArg = (Region) args[1]; regionArg.set(INITIAL_MAGNIFICATION_REGION); return null; - }).when(mMockWindowManager).getMagnificationRegion(anyInt(), (Region) anyObject()); + }).when(mMockWindowManager).getMagnificationRegion(anyInt(), any(Region.class)); } private void resetMockWindowManager() { @@ -1201,6 +1213,19 @@ public class FullScreenMagnificationControllerTest { magnifiedBounds.centerY() - scale * center.y); } + private MagnificationConfig buildConfig(float scale, float centerX, float centerY) { + return new MagnificationConfig.Builder().setMode( + MAGNIFICATION_MODE_FULLSCREEN).setScale(scale).setCenterX(centerX).setCenterY( + centerY).build(); + } + + private void assertConfigEquals(MagnificationConfig expected, MagnificationConfig result) { + assertEquals(expected.getMode(), result.getMode()); + assertEquals(expected.getScale(), result.getScale(), 0f); + assertEquals(expected.getCenterX(), result.getCenterX(), 0f); + assertEquals(expected.getCenterY(), result.getCenterY(), 0f); + } + private MagnificationSpec getInterpolatedMagSpec(MagnificationSpec start, MagnificationSpec end, float fraction) { MagnificationSpec interpolatedSpec = new MagnificationSpec(); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java index 0054fc3289320..c48d618a32b1b 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java @@ -429,6 +429,21 @@ public class MagnificationControllerTest { verify(mWindowMagnificationManager).persistScale(eq(TEST_DISPLAY)); } + @Test + public void onSourceBoundsChanged_notifyMagnificationChanged() { + Rect rect = new Rect(0, 0, 100, 120); + Region region = new Region(rect); + + mMagnificationController.onSourceBoundsChanged(TEST_DISPLAY, rect); + + final ArgumentCaptor configCaptor = ArgumentCaptor.forClass( + MagnificationConfig.class); + verify(mService).notifyMagnificationChanged(eq(TEST_DISPLAY), eq(region), + configCaptor.capture()); + assertEquals(rect.exactCenterX(), configCaptor.getValue().getCenterX(), 0); + assertEquals(rect.exactCenterY(), configCaptor.getValue().getCenterY(), 0); + } + @Test public void onAccessibilityActionPerformed_magnifierEnabled_showMagnificationButton() throws RemoteException {