From 21a62f3c8791dc2788f62f8a641c30929be8845f Mon Sep 17 00:00:00 2001 From: Daniel Hsieh Date: Wed, 8 Dec 2021 15:18:37 +0000 Subject: [PATCH] Support following typing foucs in window mode [1/n]. There are 2 milestones in this feature. 1. Refactor the callbacks for Accessibility in WindowManagerInternal. 2. Implement this feature in such new architecture. This CL is for the 1st milestone. The goal of refactor: When the window manager invokes callbacks which are related to contextual changes affecting the screen magnification feature, it will be handle by the MagnificationController first now. Then, it will dispatch the events to the activated magnification controller such as FullScreenMagnificationController or WindowMagnificationManager. We use delegate design pattern to make MagnificationController as proxy. It will assign a specific delegate when the activated controller is changed. Then, it will dispatch the events from window manager to activated magnification controller. Therefore, the activated magnification controller will handle this event. For now, we introduce WindowManagerEventDispatcher in AccessibilityControllerInternalImpl to pass the callback events to MagnificationController. However, AccessibilityControllerInternalImpl would be refactored since it should have no nested class relation with AccessibilityController. Bug: 194668976 Test: atest FullScreenMagnificationControllerTest atest WindowMagnificationManagerTest atest MagnificationControllerTest atest CtsAccessibilityServiceTestCases Change-Id: Ic4d87c48a15b9179afeda48132635adc8e86107c --- .../FullScreenMagnificationController.java | 25 +++- .../MagnificationController.java | 51 ++++++- .../WindowMagnificationManager.java | 11 +- .../server/wm/AccessibilityController.java | 140 +++++++++++------- .../server/wm/WindowManagerInternal.java | 26 ++++ .../server/wm/WindowManagerService.java | 6 +- .../MagnificationControllerTest.java | 122 ++++++++++++--- 7 files changed, 300 insertions(+), 81 deletions(-) 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 51e34178e80cd..38615feeba48b 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java @@ -63,7 +63,8 @@ import java.util.Locale; * magnification region. If a value is out of bounds, it will be adjusted to guarantee these * constraints. */ -public class FullScreenMagnificationController { +public class FullScreenMagnificationController implements + WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks { private static final boolean DEBUG = false; private static final String LOG_TAG = "FullScreenMagnificationController"; @@ -85,6 +86,8 @@ public class FullScreenMagnificationController { @GuardedBy("mLock") private final SparseArray mDisplays = new SparseArray<>(0); + private final Rect mTempRect = new Rect(); + /** * This class implements {@link WindowManagerInternal.MagnificationCallbacks} and holds * magnification information per display. @@ -727,6 +730,26 @@ public class FullScreenMagnificationController { } } + @Override + public void onRectangleOnScreenRequested(int displayId, int left, int top, int right, + int bottom) { + synchronized (mLock) { + final DisplayMagnification display = mDisplays.get(displayId); + if (display == null) { + return; + } + if (!display.isMagnifying()) { + return; + } + final Rect magnifiedRegionBounds = mTempRect; + display.getMagnifiedFrameInContentCoordsLocked(magnifiedRegionBounds); + if (magnifiedRegionBounds.contains(left, top, right, bottom)) { + return; + } + display.onRectangleOnScreenRequested(left, top, right, bottom); + } + } + /** * Remove the display magnification with given id. * 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 d430f6b032c15..791da694c8117 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java @@ -40,7 +40,9 @@ import android.view.accessibility.MagnificationAnimationCallback; import com.android.internal.accessibility.util.AccessibilityStatsLogUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; import com.android.server.accessibility.AccessibilityManagerService; +import com.android.server.wm.WindowManagerInternal; /** * Handles all magnification controllers initialization, generic interactions, @@ -68,7 +70,8 @@ import com.android.server.accessibility.AccessibilityManagerService; */ public class MagnificationController implements WindowMagnificationManager.Callback, MagnificationGestureHandler.Callback, - FullScreenMagnificationController.MagnificationInfoChangedCallback { + FullScreenMagnificationController.MagnificationInfoChangedCallback, + WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks { private static final boolean DEBUG = false; private static final String TAG = "MagnificationController"; @@ -96,6 +99,11 @@ public class MagnificationController implements WindowMagnificationManager.Callb private long mWindowModeEnabledTime = 0; private long mFullScreenModeEnabledTime = 0; + @GuardedBy("mLock") + @Nullable + private WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks + mAccessibilityCallbacksDelegate; + /** * A callback to inform the magnification transition result on the given display. */ @@ -115,6 +123,8 @@ public class MagnificationController implements WindowMagnificationManager.Callb mLock = lock; mContext = context; mScaleProvider = scaleProvider; + LocalServices.getService(WindowManagerInternal.class) + .getAccessibilityController().setUiChangesForAccessibilityCallbacks(this); } @VisibleForTesting @@ -292,6 +302,37 @@ public class MagnificationController implements WindowMagnificationManager.Callb return false; } + @GuardedBy("mLock") + private void setActivatedModeAndSwitchDelegate(int mode) { + mActivatedMode = mode; + assignMagnificationWindowManagerDelegateByMode(mode); + } + + private void assignMagnificationWindowManagerDelegateByMode(int mode) { + synchronized (mLock) { + if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) { + mAccessibilityCallbacksDelegate = getFullScreenMagnificationController(); + } else if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) { + mAccessibilityCallbacksDelegate = getWindowMagnificationMgr(); + } else { + mAccessibilityCallbacksDelegate = null; + } + } + } + + @Override + public void onRectangleOnScreenRequested(int displayId, int left, int top, int right, + int bottom) { + WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks + delegate; + synchronized (mLock) { + delegate = mAccessibilityCallbacksDelegate; + } + if (delegate != null) { + delegate.onRectangleOnScreenRequested(displayId, left, top, right, bottom); + } + } + @Override public void onRequestMagnificationSpec(int displayId, int serviceId) { final WindowMagnificationManager windowMagnificationManager; @@ -314,7 +355,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb mWindowModeEnabledTime = SystemClock.uptimeMillis(); synchronized (mLock) { - mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW; + setActivatedModeAndSwitchDelegate(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); mLastActivatedMode = mActivatedMode; } logMagnificationModeWithImeOnIfNeeded(); @@ -324,7 +365,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb SystemClock.uptimeMillis() - mWindowModeEnabledTime); synchronized (mLock) { - mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE; + setActivatedModeAndSwitchDelegate(ACCESSIBILITY_MAGNIFICATION_MODE_NONE); } } updateMagnificationButton(displayId, ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); @@ -353,7 +394,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb mFullScreenModeEnabledTime = SystemClock.uptimeMillis(); synchronized (mLock) { - mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; + setActivatedModeAndSwitchDelegate(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); mLastActivatedMode = mActivatedMode; } logMagnificationModeWithImeOnIfNeeded(); @@ -363,7 +404,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb SystemClock.uptimeMillis() - mFullScreenModeEnabledTime); synchronized (mLock) { - mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE; + setActivatedModeAndSwitchDelegate(ACCESSIBILITY_MAGNIFICATION_MODE_NONE); } } updateMagnificationButton(displayId, ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); 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 9162064780caa..3f6ff25dafe56 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java @@ -45,6 +45,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import com.android.server.accessibility.AccessibilityTraceManager; import com.android.server.statusbar.StatusBarManagerInternal; +import com.android.server.wm.WindowManagerInternal; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -57,7 +58,8 @@ import java.lang.annotation.RetentionPolicy; * {@link MagnificationScaleProvider#constrainScale(float)} */ public class WindowMagnificationManager implements - PanningScalingHandler.MagnificationDelegate { + PanningScalingHandler.MagnificationDelegate, + WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks { private static final boolean DBG = false; @@ -263,6 +265,13 @@ public class WindowMagnificationManager implements } } + @Override + public void onRectangleOnScreenRequested(int displayId, int left, int top, int right, + int bottom) { + // TODO(b/194668976): We will implement following typing focus in window mode after + // our refactor. + } + @Override public boolean processScroll(int displayId, float distanceX, float distanceY) { moveWindowMagnification(displayId, -distanceX, -distanceY); diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index ec0b5f083a384..0396a1101c644 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -98,6 +98,7 @@ import android.view.animation.Interpolator; import com.android.internal.R; import com.android.internal.os.SomeArgs; import com.android.internal.util.TraceBuffer; +import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal; @@ -277,20 +278,6 @@ final class AccessibilityController { } } - void onRectangleOnScreenRequested(int displayId, Rect rectangle) { - if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) { - mAccessibilityTracing.logTrace( - TAG + ".onRectangleOnScreenRequested", - FLAGS_MAGNIFICATION_CALLBACK, - "displayId=" + displayId + "; rectangle={" + rectangle + "}"); - } - final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); - if (displayMagnifier != null) { - displayMagnifier.onRectangleOnScreenRequested(rectangle); - } - // Not relevant for the window observer. - } - void onWindowLayersChanged(int displayId) { if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) { @@ -634,31 +621,6 @@ final class AccessibilityController { return mForceShowMagnifiableBounds; } - void onRectangleOnScreenRequested(Rect rectangle) { - if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) { - mAccessibilityTracing.logTrace(LOG_TAG + ".onRectangleOnScreenRequested", - FLAGS_MAGNIFICATION_CALLBACK, "rectangle={" + rectangle + "}"); - } - if (DEBUG_RECTANGLE_REQUESTED) { - Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle); - } - if (!mMagnifedViewport.isMagnifying()) { - return; - } - Rect magnifiedRegionBounds = mTempRect2; - mMagnifedViewport.getMagnifiedFrameInContentCoords(magnifiedRegionBounds); - if (magnifiedRegionBounds.contains(rectangle)) { - return; - } - SomeArgs args = SomeArgs.obtain(); - args.argi1 = rectangle.left; - args.argi2 = rectangle.top; - args.argi3 = rectangle.right; - args.argi4 = rectangle.bottom; - mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED, - args).sendToTarget(); - } - void onWindowLayersChanged() { if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) { mAccessibilityTracing.logTrace( @@ -1352,7 +1314,6 @@ final class AccessibilityController { private class MyHandler extends Handler { public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1; - public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2; public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3; public static final int MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED = 4; public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5; @@ -1372,16 +1333,6 @@ final class AccessibilityController { magnifiedBounds.recycle(); } break; - case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: { - SomeArgs args = (SomeArgs) message.obj; - final int left = args.argi1; - final int top = args.argi2; - final int right = args.argi3; - final int bottom = args.argi4; - mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom); - args.recycle(); - } break; - case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: { mCallbacks.onUserContextChanged(); } break; @@ -1902,7 +1853,7 @@ final class AccessibilityController { } } - private static final class AccessibilityControllerInternalImpl + static final class AccessibilityControllerInternalImpl implements AccessibilityControllerInternal { private static AccessibilityControllerInternalImpl sInstance; @@ -1917,8 +1868,11 @@ final class AccessibilityController { private final AccessibilityTracing mTracing; private volatile long mEnabledTracingFlags; + private UiChangesForAccessibilityCallbacksDispatcher mCallbacksDispatcher; + private final Looper mLooper; private AccessibilityControllerInternalImpl(WindowManagerService service) { + mLooper = service.mH.getLooper(); mTracing = AccessibilityTracing.getInstance(service); mEnabledTracingFlags = 0L; } @@ -1972,6 +1926,90 @@ final class AccessibilityController { mTracing.logState(where, loggingTypes, callingParams, a11yDump, callingUid, callStack, timeStamp, processId, threadId, ignoreStackEntries); } + + @Override + public void setUiChangesForAccessibilityCallbacks( + UiChangesForAccessibilityCallbacks callbacks) { + if (isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) { + logTrace( + TAG + ".setAccessibilityWindowManagerCallbacks", + FLAGS_MAGNIFICATION_CALLBACK, + "callbacks={" + callbacks + "}"); + } + if (callbacks != null) { + if (mCallbacksDispatcher != null) { + throw new IllegalStateException("Accessibility window manager callback already " + + "set!"); + } + mCallbacksDispatcher = + new UiChangesForAccessibilityCallbacksDispatcher(this, mLooper, + callbacks); + } else { + if (mCallbacksDispatcher == null) { + throw new IllegalStateException("Accessibility window manager callback already " + + "cleared!"); + } + mCallbacksDispatcher = null; + } + } + + public boolean hasWindowManagerEventDispatcher() { + if (isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK + | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) { + logTrace(TAG + ".hasCallbacks", + FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK); + } + return mCallbacksDispatcher != null; + } + + public void onRectangleOnScreenRequested(int displayId, Rect rectangle) { + if (isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) { + logTrace( + TAG + ".onRectangleOnScreenRequested", + FLAGS_MAGNIFICATION_CALLBACK, + "rectangle={" + rectangle + "}"); + } + if (mCallbacksDispatcher != null) { + mCallbacksDispatcher.onRectangleOnScreenRequested(displayId, rectangle); + } + } + + private static final class UiChangesForAccessibilityCallbacksDispatcher { + + private static final String LOG_TAG = TAG_WITH_CLASS_NAME + ? "WindowManagerEventDispatcher" : TAG_WM; + + private static final boolean DEBUG_RECTANGLE_REQUESTED = false; + + private final AccessibilityControllerInternalImpl mAccessibilityTracing; + + @NonNull + private final UiChangesForAccessibilityCallbacks mCallbacks; + + private final Handler mHandler; + + UiChangesForAccessibilityCallbacksDispatcher( + AccessibilityControllerInternalImpl accessibilityControllerInternal, + Looper looper, @NonNull UiChangesForAccessibilityCallbacks callbacks) { + mAccessibilityTracing = accessibilityControllerInternal; + mCallbacks = callbacks; + mHandler = new Handler(looper); + } + + void onRectangleOnScreenRequested(int displayId, Rect rectangle) { + if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) { + mAccessibilityTracing.logTrace(LOG_TAG + ".onRectangleOnScreenRequested", + FLAGS_MAGNIFICATION_CALLBACK, "rectangle={" + rectangle + "}"); + } + if (DEBUG_RECTANGLE_REQUESTED) { + Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle); + } + final Message m = PooledLambda.obtainMessage( + mCallbacks::onRectangleOnScreenRequested, displayId, rectangle.left, + rectangle.top, rectangle.right, rectangle.bottom); + mHandler.sendMessage(m); + } + } } private static final class AccessibilityTracing { diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 34cb5ae032ba9..62c674b15f89a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -104,6 +104,32 @@ public abstract class WindowManagerInternal { void logTrace(String where, long loggingTypeFlags, String callingParams, byte[] a11yDump, int callingUid, StackTraceElement[] callStack, long timeStamp, int processId, long threadId, Set ignoreStackEntries); + + /** + * Set by the accessibility related modules which want to listen the event dispatched from + * window manager. Accessibility modules can use these callbacks to handle some display + * manipulations. + * @param callbacks The callbacks to invoke. + */ + void setUiChangesForAccessibilityCallbacks(UiChangesForAccessibilityCallbacks callbacks); + + /** + * This interface is used by window manager to dispatch some ui change events which may + * affect the screen accessibility features. + */ + interface UiChangesForAccessibilityCallbacks { + /** + * Called when an application requests a rectangle focus on the screen. + * + * @param displayId The logical display id + * @param left The rectangle left. + * @param top The rectangle top. + * @param right The rectangle right. + * @param bottom The rectangle bottom. + */ + void onRectangleOnScreenRequested(int displayId, int left, int top, int right, + int bottom); + } } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index e986fd2e46e84..6b3780a42f0d8 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2143,11 +2143,13 @@ public class WindowManagerService extends IWindowManager.Stub } public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) { + final AccessibilityController.AccessibilityControllerInternalImpl a11yControllerInternal = + AccessibilityController.getAccessibilityControllerInternal(this); synchronized (mGlobalLock) { - if (mAccessibilityController.hasCallbacks()) { + if (a11yControllerInternal.hasWindowManagerEventDispatcher()) { WindowState window = mWindowMap.get(token); if (window != null) { - mAccessibilityController.onRectangleOnScreenRequested( + a11yControllerInternal.onRectangleOnScreenRequested( window.getDisplayId(), rectangle); } } 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 ec1a0c2f1d0d7..08421de3183a2 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 @@ -55,8 +55,10 @@ import android.view.accessibility.MagnificationAnimationCallback; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.test.FakeSettingsProvider; +import com.android.server.LocalServices; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.accessibility.AccessibilityTraceManager; +import com.android.server.wm.WindowManagerInternal; import org.junit.After; import org.junit.Before; @@ -79,6 +81,7 @@ public class MagnificationControllerTest { private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY; private static final int TEST_SERVICE_ID = 1; private static final Region MAGNIFICATION_REGION = new Region(0, 0, 500, 600); + private static final Rect TEST_RECT = new Rect(0, 50, 100, 51); private static final float MAGNIFIED_CENTER_X = 100; private static final float MAGNIFIED_CENTER_Y = 200; private static final float DEFAULT_SCALE = 3f; @@ -108,6 +111,11 @@ public class MagnificationControllerTest { private MagnificationController mMagnificationController; private FullScreenMagnificationControllerStubber mScreenMagnificationControllerStubber; + @Mock + private WindowManagerInternal mMockWindowManagerInternal; + @Mock + private WindowManagerInternal.AccessibilityControllerInternal mMockA11yController; + // To mock package-private class @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = @@ -117,6 +125,12 @@ public class MagnificationControllerTest { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); FakeSettingsProvider.clearSettingsProvider(); + + LocalServices.removeServiceForTest(WindowManagerInternal.class); + LocalServices.addService(WindowManagerInternal.class, mMockWindowManagerInternal); + when(mMockWindowManagerInternal.getAccessibilityController()).thenReturn( + mMockA11yController); + mMockResolver = new MockContentResolver(); mMockResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); when(mContext.getContentResolver()).thenReturn(mMockResolver); @@ -132,8 +146,8 @@ public class MagnificationControllerTest { mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); mScreenMagnificationControllerStubber = new FullScreenMagnificationControllerStubber( mScreenMagnificationController); - mMagnificationController = spy(new MagnificationController(mService, new Object(), mContext, - mScreenMagnificationController, mWindowMagnificationManager, mScaleProvider)); + mMagnificationController = new MagnificationController(mService, new Object(), mContext, + mScreenMagnificationController, mWindowMagnificationManager, mScaleProvider); mMagnificationController.setMagnificationCapabilities( Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL); @@ -439,16 +453,65 @@ public class MagnificationControllerTest { @Test public void onWindowMagnificationActivationState_windowActivated_logWindowDuration() { - mMagnificationController.onWindowMagnificationActivationState(TEST_DISPLAY, true); + MagnificationController spyController = spy(mMagnificationController); + spyController.onWindowMagnificationActivationState(TEST_DISPLAY, true); - mMagnificationController.onWindowMagnificationActivationState(TEST_DISPLAY, false); + spyController.onWindowMagnificationActivationState(TEST_DISPLAY, false); - verify(mMagnificationController).logMagnificationUsageState( + verify(spyController).logMagnificationUsageState( eq(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW), anyLong()); } @Test - public void onWinodwModeActivated_fullScreenIsActivatedByExternal_fullScreenIsDisabled() { + public void onRectangleOnScreenRequested_fullScreenIsActivated_fullScreenDispatchEvent() { + mMagnificationController.onFullScreenMagnificationActivationState(TEST_DISPLAY, + true); + WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks + callbacks = getUiChangesForAccessibilityCallbacks(); + + callbacks.onRectangleOnScreenRequested(TEST_DISPLAY, + TEST_RECT.left, TEST_RECT.top, TEST_RECT.right, TEST_RECT.bottom); + + verify(mScreenMagnificationController).onRectangleOnScreenRequested(eq(TEST_DISPLAY), + eq(TEST_RECT.left), eq(TEST_RECT.top), eq(TEST_RECT.right), eq(TEST_RECT.bottom)); + verify(mWindowMagnificationManager, never()).onRectangleOnScreenRequested(anyInt(), + anyInt(), anyInt(), anyInt(), anyInt()); + } + + @Test + public void onRectangleOnScreenRequested_fullScreenIsInactivated_noneDispatchEvent() { + mMagnificationController.onFullScreenMagnificationActivationState(TEST_DISPLAY, + true); + mMagnificationController.onFullScreenMagnificationActivationState(TEST_DISPLAY, + false); + WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks + callbacks = getUiChangesForAccessibilityCallbacks(); + + callbacks.onRectangleOnScreenRequested(TEST_DISPLAY, + TEST_RECT.left, TEST_RECT.top, TEST_RECT.right, TEST_RECT.bottom); + + verify(mScreenMagnificationController, never()).onRectangleOnScreenRequested(anyInt(), + anyInt(), anyInt(), anyInt(), anyInt()); + verify(mWindowMagnificationManager, never()).onRectangleOnScreenRequested(anyInt(), + anyInt(), anyInt(), anyInt(), anyInt()); + } + + @Test + public void onRectangleOnScreenRequested_NoneIsActivated_noneDispatchEvent() { + WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks + callbacks = getUiChangesForAccessibilityCallbacks(); + + callbacks.onRectangleOnScreenRequested(TEST_DISPLAY, + TEST_RECT.left, TEST_RECT.top, TEST_RECT.right, TEST_RECT.bottom); + + verify(mScreenMagnificationController, never()).onRectangleOnScreenRequested( + eq(TEST_DISPLAY), anyInt(), anyInt(), anyInt(), anyInt()); + verify(mWindowMagnificationManager, never()).onRectangleOnScreenRequested(anyInt(), + anyInt(), anyInt(), anyInt(), anyInt()); + } + + @Test + public void onWindowModeActivated_fullScreenIsActivatedByExternal_fullScreenIsDisabled() { mScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY, DEFAULT_SCALE, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y, true, TEST_SERVICE_ID); @@ -461,11 +524,12 @@ public class MagnificationControllerTest { @Test public void onFullScreenMagnificationActivationState_fullScreenActivated_logFullScreenDuration() { - mMagnificationController.onFullScreenMagnificationActivationState(TEST_DISPLAY, true); + MagnificationController spyController = spy(mMagnificationController); + spyController.onFullScreenMagnificationActivationState(TEST_DISPLAY, true); - mMagnificationController.onFullScreenMagnificationActivationState(TEST_DISPLAY, false); + spyController.onFullScreenMagnificationActivationState(TEST_DISPLAY, false); - verify(mMagnificationController).logMagnificationUsageState( + verify(spyController).logMagnificationUsageState( eq(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN), anyLong()); } @@ -627,43 +691,48 @@ public class MagnificationControllerTest { @Test public void imeWindowStateShown_windowMagnifying_logWindowMode() { - mMagnificationController.onWindowMagnificationActivationState(TEST_DISPLAY, true); + MagnificationController spyController = spy(mMagnificationController); + spyController.onWindowMagnificationActivationState(TEST_DISPLAY, true); - mMagnificationController.onImeWindowVisibilityChanged(true); + spyController.onImeWindowVisibilityChanged(true); - verify(mMagnificationController).logMagnificationModeWithIme( + verify(spyController).logMagnificationModeWithIme( eq(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW)); } @Test public void imeWindowStateShown_fullScreenMagnifying_logFullScreenMode() { - mMagnificationController.onFullScreenMagnificationActivationState(TEST_DISPLAY, true); + MagnificationController spyController = spy(mMagnificationController); + spyController.onFullScreenMagnificationActivationState(TEST_DISPLAY, true); - mMagnificationController.onImeWindowVisibilityChanged(true); + spyController.onImeWindowVisibilityChanged(true); - verify(mMagnificationController).logMagnificationModeWithIme( + verify(spyController).logMagnificationModeWithIme( eq(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN)); } @Test public void imeWindowStateShown_noMagnifying_noLogAnyMode() { - mMagnificationController.onImeWindowVisibilityChanged(true); + MagnificationController spyController = spy(mMagnificationController); + spyController.onImeWindowVisibilityChanged(true); - verify(mMagnificationController, never()).logMagnificationModeWithIme(anyInt()); + verify(spyController, never()).logMagnificationModeWithIme(anyInt()); } @Test public void imeWindowStateHidden_windowMagnifying_noLogAnyMode() { - mMagnificationController.onFullScreenMagnificationActivationState(TEST_DISPLAY, true); + MagnificationController spyController = spy(mMagnificationController); + spyController.onFullScreenMagnificationActivationState(TEST_DISPLAY, true); - verify(mMagnificationController, never()).logMagnificationModeWithIme(anyInt()); + verify(spyController, never()).logMagnificationModeWithIme(anyInt()); } @Test public void imeWindowStateHidden_fullScreenMagnifying_noLogAnyMode() { - mMagnificationController.onWindowMagnificationActivationState(TEST_DISPLAY, true); + MagnificationController spyController = spy(mMagnificationController); + spyController.onWindowMagnificationActivationState(TEST_DISPLAY, true); - verify(mMagnificationController, never()).logMagnificationModeWithIme(anyInt()); + verify(spyController, never()).logMagnificationModeWithIme(anyInt()); } @Test @@ -718,6 +787,17 @@ public class MagnificationControllerTest { MAGNIFIED_CENTER_X).setCenterY(MAGNIFIED_CENTER_Y).build(); } + private WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks + getUiChangesForAccessibilityCallbacks() { + ArgumentCaptor captor = ArgumentCaptor.forClass( + WindowManagerInternal.AccessibilityControllerInternal + .UiChangesForAccessibilityCallbacks.class); + verify(mMockWindowManagerInternal.getAccessibilityController()) + .setUiChangesForAccessibilityCallbacks(captor.capture()); + return captor.getValue(); + } + /** * Stubs public methods to simulate the real beahviours. */