Loading services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +70 −8 Original line number Diff line number Diff line Loading @@ -16,9 +16,11 @@ package com.android.server.accessibility; import android.annotation.MainThread; import android.content.Context; import android.graphics.Region; import android.os.PowerManager; import android.provider.Settings; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; Loading @@ -33,6 +35,7 @@ import android.view.accessibility.AccessibilityEvent; import com.android.server.LocalServices; import com.android.server.accessibility.gestures.TouchExplorer; import com.android.server.accessibility.magnification.MagnificationGestureHandler; import com.android.server.accessibility.magnification.WindowMagnificationGestureHandler; import com.android.server.policy.WindowManagerPolicy; import java.util.ArrayList; Loading Loading @@ -424,14 +427,9 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0 || ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) || ((mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0)) { final boolean detectControlGestures = (mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0; final boolean triggerable = (mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0; MagnificationGestureHandler magnificationGestureHandler = new FullScreenMagnificationGestureHandler(displayContext, mAms.getMagnificationController(), detectControlGestures, triggerable, displayId); final MagnificationGestureHandler magnificationGestureHandler = createMagnificationGestureHandler(displayId, displayContext); addFirstEventHandler(displayId, magnificationGestureHandler); mMagnificationGestureHandler.put(displayId, magnificationGestureHandler); } Loading Loading @@ -527,6 +525,25 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo resetStreamState(); } private MagnificationGestureHandler createMagnificationGestureHandler( int displayId, Context displayContext) { final boolean detectControlGestures = (mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0; final boolean triggerable = (mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0; MagnificationGestureHandler magnificationGestureHandler; if (mAms.getMagnificationMode(displayId) == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW && triggerable) { magnificationGestureHandler = new WindowMagnificationGestureHandler( displayContext, mAms.getWindowMagnificationMgr(), displayId); } else { magnificationGestureHandler = new FullScreenMagnificationGestureHandler( displayContext, mAms.getMagnificationController(), detectControlGestures, triggerable, displayId); } return magnificationGestureHandler; } void resetStreamState() { if (mTouchScreenStreamState != null) { mTouchScreenStreamState.reset(); Loading @@ -544,6 +561,51 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo /* ignore */ } /** * Called when the magnification mode is changed on specific display. * @param display The logical display */ @MainThread public void onMagnificationModeChanged(Display display) { final int displayId = display.getDisplayId(); final MagnificationGestureHandler magnificationGestureHandler = mMagnificationGestureHandler.get(displayId); if (magnificationGestureHandler == null) { return; } magnificationGestureHandler.onDestroy(); final MagnificationGestureHandler currentMagnificationGestureHandler = createMagnificationGestureHandler(displayId, mContext.createDisplayContext(display)); switchEventStreamTransformation(displayId, magnificationGestureHandler, currentMagnificationGestureHandler); mMagnificationGestureHandler.put(displayId, currentMagnificationGestureHandler); } @MainThread private void switchEventStreamTransformation(int displayId, EventStreamTransformation oldStreamTransformation, EventStreamTransformation currentStreamTransformation) { EventStreamTransformation eventStreamTransformation = mEventHandler.get(displayId); if (eventStreamTransformation == null) { return; } if (eventStreamTransformation == oldStreamTransformation) { currentStreamTransformation.setNext(oldStreamTransformation.getNext()); mEventHandler.put(displayId, currentStreamTransformation); } else { while (eventStreamTransformation != null) { if (eventStreamTransformation.getNext() == oldStreamTransformation) { eventStreamTransformation.setNext(currentStreamTransformation); currentStreamTransformation.setNext(oldStreamTransformation.getNext()); return; } else { eventStreamTransformation = eventStreamTransformation.getNext(); } } } } /** * Keeps state of event streams observed for an input device with a certain source. * Provides information about whether motion and key events should be processed by accessibility Loading services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +58 −0 Original line number Diff line number Diff line Loading @@ -1368,6 +1368,28 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return relevantEventTypes; } private void updateMagnificationModeChangeSettingsLocked() { mMainHandler.sendMessage(obtainMessage( AccessibilityManagerService::notifyMagnificationModeChangeToInputFilter, this)); } private void notifyMagnificationModeChangeToInputFilter() { synchronized (mLock) { if (!mHasInputFilter) { return; } // TODO: notify the mode change on specified display. final ArrayList<Display> displays = getValidDisplayList(); for (int i = 0; i < displays.size(); i++) { final Display display = displays.get(i); if (display != null) { mInputFilter.onMagnificationModeChanged(display); } } } } private static boolean isClientInPackageWhitelist( @Nullable AccessibilityServiceInfo serviceInfo, Client client) { if (serviceInfo == null) return false; Loading Loading @@ -1744,6 +1766,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub scheduleUpdateClientsIfNeededLocked(userState); updateAccessibilityShortcutKeyTargetsLocked(userState); updateAccessibilityButtonTargetsLocked(userState); updateMagnificationModeChangeSettingsLocked(); } private void updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState) { Loading Loading @@ -1840,6 +1863,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub somethingChanged |= readAccessibilityShortcutKeySettingLocked(userState); somethingChanged |= readAccessibilityButtonSettingsLocked(userState); somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState); somethingChanged |= readMagnificationModeLocked(userState); return somethingChanged; } Loading Loading @@ -2988,6 +3012,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final Uri mUserInteractiveUiTimeoutUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS); private final Uri mMagnificationModeUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE); public AccessibilityContentObserver(Handler handler) { super(handler); } Loading Loading @@ -3018,6 +3045,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mUserNonInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mUserInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mMagnificationModeUri, false, this, UserHandle.USER_ALL); } @Override Loading Loading @@ -3066,9 +3095,38 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } else if (mUserNonInteractiveUiTimeoutUri.equals(uri) || mUserInteractiveUiTimeoutUri.equals(uri)) { readUserRecommendedUiTimeoutSettingsLocked(userState); } else if (mMagnificationModeUri.equals(uri)) { if (readMagnificationModeLocked(userState)) { updateMagnificationModeChangeSettingsLocked(); } } } } } //TODO: support multi-display. /** * Gets the magnification mode of the specified display. * @param displayId The logical displayId. * @return magnification mode. It's either ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN or * ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW. */ public int getMagnificationMode(int displayId) { synchronized (mLock) { return getCurrentUserStateLocked().getMagnificationModeLocked(); } } private boolean readMagnificationModeLocked(AccessibilityUserState userState) { final int magnificationMode = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, userState.mUserId); if (magnificationMode != userState.getMagnificationModeLocked()) { userState.setMagnificationModeLocked(magnificationMode); return true; } return false; } @Override Loading services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +23 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_K import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_MASK; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; import static android.view.accessibility.AccessibilityManager.ShortcutType; Loading Loading @@ -110,6 +111,8 @@ class AccessibilityUserState { private int mNonInteractiveUiTimeout = 0; private int mInteractiveUiTimeout = 0; private int mLastSentClientState = -1; // The magnification mode of default display. private int mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; private Context mContext; Loading Loading @@ -159,6 +162,7 @@ class AccessibilityUserState { mIsAutoclickEnabled = false; mUserNonInteractiveUiTimeout = 0; mUserInteractiveUiTimeout = 0; mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; } void addServiceLocked(AccessibilityServiceConnection serviceConnection) { Loading Loading @@ -567,6 +571,25 @@ class AccessibilityUserState { || mAccessibilityButtonTargets.contains(MAGNIFICATION_CONTROLLER_NAME); } /** * Gets the magnification mode of default display. * @return magnification mode * * @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN * @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW */ public int getMagnificationModeLocked() { return mMagnificationMode; } /** * Sets the magnification mode of default display. * @param mode The magnification mode. */ public void setMagnificationModeLocked(int mode) { mMagnificationMode = mode; } /** * Disable both shortcuts' magnification function. */ Loading services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java +76 −0 Original line number Diff line number Diff line Loading @@ -28,14 +28,18 @@ import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEA import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.annotation.Nullable; import android.content.Context; import android.hardware.display.DisplayManagerGlobal; import android.os.Looper; import android.os.SystemClock; import android.provider.Settings; import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; Loading @@ -48,6 +52,8 @@ import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.server.accessibility.gestures.TouchExplorer; import com.android.server.accessibility.magnification.MagnificationGestureHandler; import com.android.server.accessibility.magnification.WindowMagnificationGestureHandler; import org.junit.After; import org.junit.Before; Loading Loading @@ -241,6 +247,63 @@ public class AccessibilityInputFilterTest { assertEquals(1, mCaptor1.mEvents.size()); } @Test public void testEnabledFeatures_windowMagnificationMode_expectedMagnificationGestureHandler() { prepareLooper(); doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW).when( mAms).getMagnificationMode(DEFAULT_DISPLAY); mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures); MagnificationGestureHandler handler = getMagnificationGestureHandlerFromEventHandler(DEFAULT_DISPLAY); assertNotNull(handler); assertEquals(WindowMagnificationGestureHandler.class, handler.getClass()); } @Test public void testChangeMagnificationModeToWindow_expectedMagnificationGestureHandler() { prepareLooper(); doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN).when( mAms).getMagnificationMode(DEFAULT_DISPLAY); mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures); doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW).when( mAms).getMagnificationMode(DEFAULT_DISPLAY); EventStreamTransformation nextEventStream = getMagnificationGestureHandlerFromEventHandler( DEFAULT_DISPLAY).getNext(); mA11yInputFilter.onMagnificationModeChanged(mDisplayList.get(DEFAULT_DISPLAY)); MagnificationGestureHandler handler = getMagnificationGestureHandlerFromEventHandler(DEFAULT_DISPLAY); assertNotNull(handler); assertEquals(WindowMagnificationGestureHandler.class, handler.getClass()); assertEquals(nextEventStream.getClass(), handler.getNext().getClass()); } @Test public void testChangeMagnificationModeToWindow_magnifierFeature_expectedMagnificationGestureHandler() { prepareLooper(); doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN).when( mAms).getMagnificationMode(DEFAULT_DISPLAY); final int feature = FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER | FLAG_FEATURE_TOUCH_EXPLORATION; mA11yInputFilter.setUserAndEnabledFeatures(0, feature); doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW).when( mAms).getMagnificationMode(DEFAULT_DISPLAY); EventStreamTransformation nextEventStream = getMagnificationGestureHandlerFromEventHandler( DEFAULT_DISPLAY).getNext(); mA11yInputFilter.onMagnificationModeChanged(mDisplayList.get(DEFAULT_DISPLAY)); MagnificationGestureHandler handler = getMagnificationGestureHandlerFromEventHandler(DEFAULT_DISPLAY); assertNotNull(handler); assertEquals(WindowMagnificationGestureHandler.class, handler.getClass()); assertEquals(nextEventStream.getClass(), handler.getNext().getClass()); } private static void prepareLooper() { if (Looper.myLooper() == null) { Looper.prepare(); Loading Loading @@ -274,4 +337,17 @@ public class AccessibilityInputFilterTest { ev.setSource(source); return ev; } @Nullable private MagnificationGestureHandler getMagnificationGestureHandlerFromEventHandler( int displayId) { EventStreamTransformation next = mEventHandler.get(displayId); while (next != null) { if (next instanceof MagnificationGestureHandler) { return (MagnificationGestureHandler) next; } next = next.getNext(); } return null; } } services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java +16 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_K import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW; import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; import static android.view.accessibility.AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED; import static android.view.accessibility.AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED; Loading Loading @@ -116,6 +118,7 @@ public class AccessibilityUserStateTest { mUserState.setAutoclickEnabledLocked(true); mUserState.setUserNonInteractiveUiTimeoutLocked(30); mUserState.setUserInteractiveUiTimeoutLocked(30); mUserState.setMagnificationModeLocked(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); mUserState.onSwitchToAnotherUserLocked(); Loading @@ -134,6 +137,8 @@ public class AccessibilityUserStateTest { assertFalse(mUserState.isAutoclickEnabledLocked()); assertEquals(0, mUserState.getUserNonInteractiveUiTimeoutLocked()); assertEquals(0, mUserState.getUserInteractiveUiTimeoutLocked()); assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, mUserState.getMagnificationModeLocked()); } @Test Loading Loading @@ -298,6 +303,17 @@ public class AccessibilityUserStateTest { assertFalse(mUserState.isShortcutTargetInstalledLocked(invalidTarget.flattenToString())); } @Test public void setWindowMagnificationMode_returnExpectedMagnificationMode() { assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, mUserState.getMagnificationModeLocked()); mUserState.setMagnificationModeLocked(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW, mUserState.getMagnificationModeLocked()); } private int getSecureIntForUser(String key, int userId) { return Settings.Secure.getIntForUser(mMockResolver, key, -1, userId); } Loading Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +70 −8 Original line number Diff line number Diff line Loading @@ -16,9 +16,11 @@ package com.android.server.accessibility; import android.annotation.MainThread; import android.content.Context; import android.graphics.Region; import android.os.PowerManager; import android.provider.Settings; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; Loading @@ -33,6 +35,7 @@ import android.view.accessibility.AccessibilityEvent; import com.android.server.LocalServices; import com.android.server.accessibility.gestures.TouchExplorer; import com.android.server.accessibility.magnification.MagnificationGestureHandler; import com.android.server.accessibility.magnification.WindowMagnificationGestureHandler; import com.android.server.policy.WindowManagerPolicy; import java.util.ArrayList; Loading Loading @@ -424,14 +427,9 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0 || ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) || ((mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0)) { final boolean detectControlGestures = (mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0; final boolean triggerable = (mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0; MagnificationGestureHandler magnificationGestureHandler = new FullScreenMagnificationGestureHandler(displayContext, mAms.getMagnificationController(), detectControlGestures, triggerable, displayId); final MagnificationGestureHandler magnificationGestureHandler = createMagnificationGestureHandler(displayId, displayContext); addFirstEventHandler(displayId, magnificationGestureHandler); mMagnificationGestureHandler.put(displayId, magnificationGestureHandler); } Loading Loading @@ -527,6 +525,25 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo resetStreamState(); } private MagnificationGestureHandler createMagnificationGestureHandler( int displayId, Context displayContext) { final boolean detectControlGestures = (mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0; final boolean triggerable = (mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0; MagnificationGestureHandler magnificationGestureHandler; if (mAms.getMagnificationMode(displayId) == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW && triggerable) { magnificationGestureHandler = new WindowMagnificationGestureHandler( displayContext, mAms.getWindowMagnificationMgr(), displayId); } else { magnificationGestureHandler = new FullScreenMagnificationGestureHandler( displayContext, mAms.getMagnificationController(), detectControlGestures, triggerable, displayId); } return magnificationGestureHandler; } void resetStreamState() { if (mTouchScreenStreamState != null) { mTouchScreenStreamState.reset(); Loading @@ -544,6 +561,51 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo /* ignore */ } /** * Called when the magnification mode is changed on specific display. * @param display The logical display */ @MainThread public void onMagnificationModeChanged(Display display) { final int displayId = display.getDisplayId(); final MagnificationGestureHandler magnificationGestureHandler = mMagnificationGestureHandler.get(displayId); if (magnificationGestureHandler == null) { return; } magnificationGestureHandler.onDestroy(); final MagnificationGestureHandler currentMagnificationGestureHandler = createMagnificationGestureHandler(displayId, mContext.createDisplayContext(display)); switchEventStreamTransformation(displayId, magnificationGestureHandler, currentMagnificationGestureHandler); mMagnificationGestureHandler.put(displayId, currentMagnificationGestureHandler); } @MainThread private void switchEventStreamTransformation(int displayId, EventStreamTransformation oldStreamTransformation, EventStreamTransformation currentStreamTransformation) { EventStreamTransformation eventStreamTransformation = mEventHandler.get(displayId); if (eventStreamTransformation == null) { return; } if (eventStreamTransformation == oldStreamTransformation) { currentStreamTransformation.setNext(oldStreamTransformation.getNext()); mEventHandler.put(displayId, currentStreamTransformation); } else { while (eventStreamTransformation != null) { if (eventStreamTransformation.getNext() == oldStreamTransformation) { eventStreamTransformation.setNext(currentStreamTransformation); currentStreamTransformation.setNext(oldStreamTransformation.getNext()); return; } else { eventStreamTransformation = eventStreamTransformation.getNext(); } } } } /** * Keeps state of event streams observed for an input device with a certain source. * Provides information about whether motion and key events should be processed by accessibility Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +58 −0 Original line number Diff line number Diff line Loading @@ -1368,6 +1368,28 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return relevantEventTypes; } private void updateMagnificationModeChangeSettingsLocked() { mMainHandler.sendMessage(obtainMessage( AccessibilityManagerService::notifyMagnificationModeChangeToInputFilter, this)); } private void notifyMagnificationModeChangeToInputFilter() { synchronized (mLock) { if (!mHasInputFilter) { return; } // TODO: notify the mode change on specified display. final ArrayList<Display> displays = getValidDisplayList(); for (int i = 0; i < displays.size(); i++) { final Display display = displays.get(i); if (display != null) { mInputFilter.onMagnificationModeChanged(display); } } } } private static boolean isClientInPackageWhitelist( @Nullable AccessibilityServiceInfo serviceInfo, Client client) { if (serviceInfo == null) return false; Loading Loading @@ -1744,6 +1766,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub scheduleUpdateClientsIfNeededLocked(userState); updateAccessibilityShortcutKeyTargetsLocked(userState); updateAccessibilityButtonTargetsLocked(userState); updateMagnificationModeChangeSettingsLocked(); } private void updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState) { Loading Loading @@ -1840,6 +1863,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub somethingChanged |= readAccessibilityShortcutKeySettingLocked(userState); somethingChanged |= readAccessibilityButtonSettingsLocked(userState); somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState); somethingChanged |= readMagnificationModeLocked(userState); return somethingChanged; } Loading Loading @@ -2988,6 +3012,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final Uri mUserInteractiveUiTimeoutUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS); private final Uri mMagnificationModeUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE); public AccessibilityContentObserver(Handler handler) { super(handler); } Loading Loading @@ -3018,6 +3045,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mUserNonInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mUserInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mMagnificationModeUri, false, this, UserHandle.USER_ALL); } @Override Loading Loading @@ -3066,9 +3095,38 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } else if (mUserNonInteractiveUiTimeoutUri.equals(uri) || mUserInteractiveUiTimeoutUri.equals(uri)) { readUserRecommendedUiTimeoutSettingsLocked(userState); } else if (mMagnificationModeUri.equals(uri)) { if (readMagnificationModeLocked(userState)) { updateMagnificationModeChangeSettingsLocked(); } } } } } //TODO: support multi-display. /** * Gets the magnification mode of the specified display. * @param displayId The logical displayId. * @return magnification mode. It's either ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN or * ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW. */ public int getMagnificationMode(int displayId) { synchronized (mLock) { return getCurrentUserStateLocked().getMagnificationModeLocked(); } } private boolean readMagnificationModeLocked(AccessibilityUserState userState) { final int magnificationMode = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, userState.mUserId); if (magnificationMode != userState.getMagnificationModeLocked()) { userState.setMagnificationModeLocked(magnificationMode); return true; } return false; } @Override Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +23 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_K import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_MASK; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; import static android.view.accessibility.AccessibilityManager.ShortcutType; Loading Loading @@ -110,6 +111,8 @@ class AccessibilityUserState { private int mNonInteractiveUiTimeout = 0; private int mInteractiveUiTimeout = 0; private int mLastSentClientState = -1; // The magnification mode of default display. private int mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; private Context mContext; Loading Loading @@ -159,6 +162,7 @@ class AccessibilityUserState { mIsAutoclickEnabled = false; mUserNonInteractiveUiTimeout = 0; mUserInteractiveUiTimeout = 0; mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; } void addServiceLocked(AccessibilityServiceConnection serviceConnection) { Loading Loading @@ -567,6 +571,25 @@ class AccessibilityUserState { || mAccessibilityButtonTargets.contains(MAGNIFICATION_CONTROLLER_NAME); } /** * Gets the magnification mode of default display. * @return magnification mode * * @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN * @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW */ public int getMagnificationModeLocked() { return mMagnificationMode; } /** * Sets the magnification mode of default display. * @param mode The magnification mode. */ public void setMagnificationModeLocked(int mode) { mMagnificationMode = mode; } /** * Disable both shortcuts' magnification function. */ Loading
services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java +76 −0 Original line number Diff line number Diff line Loading @@ -28,14 +28,18 @@ import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEA import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.annotation.Nullable; import android.content.Context; import android.hardware.display.DisplayManagerGlobal; import android.os.Looper; import android.os.SystemClock; import android.provider.Settings; import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; Loading @@ -48,6 +52,8 @@ import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.server.accessibility.gestures.TouchExplorer; import com.android.server.accessibility.magnification.MagnificationGestureHandler; import com.android.server.accessibility.magnification.WindowMagnificationGestureHandler; import org.junit.After; import org.junit.Before; Loading Loading @@ -241,6 +247,63 @@ public class AccessibilityInputFilterTest { assertEquals(1, mCaptor1.mEvents.size()); } @Test public void testEnabledFeatures_windowMagnificationMode_expectedMagnificationGestureHandler() { prepareLooper(); doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW).when( mAms).getMagnificationMode(DEFAULT_DISPLAY); mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures); MagnificationGestureHandler handler = getMagnificationGestureHandlerFromEventHandler(DEFAULT_DISPLAY); assertNotNull(handler); assertEquals(WindowMagnificationGestureHandler.class, handler.getClass()); } @Test public void testChangeMagnificationModeToWindow_expectedMagnificationGestureHandler() { prepareLooper(); doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN).when( mAms).getMagnificationMode(DEFAULT_DISPLAY); mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures); doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW).when( mAms).getMagnificationMode(DEFAULT_DISPLAY); EventStreamTransformation nextEventStream = getMagnificationGestureHandlerFromEventHandler( DEFAULT_DISPLAY).getNext(); mA11yInputFilter.onMagnificationModeChanged(mDisplayList.get(DEFAULT_DISPLAY)); MagnificationGestureHandler handler = getMagnificationGestureHandlerFromEventHandler(DEFAULT_DISPLAY); assertNotNull(handler); assertEquals(WindowMagnificationGestureHandler.class, handler.getClass()); assertEquals(nextEventStream.getClass(), handler.getNext().getClass()); } @Test public void testChangeMagnificationModeToWindow_magnifierFeature_expectedMagnificationGestureHandler() { prepareLooper(); doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN).when( mAms).getMagnificationMode(DEFAULT_DISPLAY); final int feature = FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER | FLAG_FEATURE_TOUCH_EXPLORATION; mA11yInputFilter.setUserAndEnabledFeatures(0, feature); doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW).when( mAms).getMagnificationMode(DEFAULT_DISPLAY); EventStreamTransformation nextEventStream = getMagnificationGestureHandlerFromEventHandler( DEFAULT_DISPLAY).getNext(); mA11yInputFilter.onMagnificationModeChanged(mDisplayList.get(DEFAULT_DISPLAY)); MagnificationGestureHandler handler = getMagnificationGestureHandlerFromEventHandler(DEFAULT_DISPLAY); assertNotNull(handler); assertEquals(WindowMagnificationGestureHandler.class, handler.getClass()); assertEquals(nextEventStream.getClass(), handler.getNext().getClass()); } private static void prepareLooper() { if (Looper.myLooper() == null) { Looper.prepare(); Loading Loading @@ -274,4 +337,17 @@ public class AccessibilityInputFilterTest { ev.setSource(source); return ev; } @Nullable private MagnificationGestureHandler getMagnificationGestureHandlerFromEventHandler( int displayId) { EventStreamTransformation next = mEventHandler.get(displayId); while (next != null) { if (next instanceof MagnificationGestureHandler) { return (MagnificationGestureHandler) next; } next = next.getNext(); } return null; } }
services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java +16 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_K import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW; import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; import static android.view.accessibility.AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED; import static android.view.accessibility.AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED; Loading Loading @@ -116,6 +118,7 @@ public class AccessibilityUserStateTest { mUserState.setAutoclickEnabledLocked(true); mUserState.setUserNonInteractiveUiTimeoutLocked(30); mUserState.setUserInteractiveUiTimeoutLocked(30); mUserState.setMagnificationModeLocked(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); mUserState.onSwitchToAnotherUserLocked(); Loading @@ -134,6 +137,8 @@ public class AccessibilityUserStateTest { assertFalse(mUserState.isAutoclickEnabledLocked()); assertEquals(0, mUserState.getUserNonInteractiveUiTimeoutLocked()); assertEquals(0, mUserState.getUserInteractiveUiTimeoutLocked()); assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, mUserState.getMagnificationModeLocked()); } @Test Loading Loading @@ -298,6 +303,17 @@ public class AccessibilityUserStateTest { assertFalse(mUserState.isShortcutTargetInstalledLocked(invalidTarget.flattenToString())); } @Test public void setWindowMagnificationMode_returnExpectedMagnificationMode() { assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, mUserState.getMagnificationModeLocked()); mUserState.setMagnificationModeLocked(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW, mUserState.getMagnificationModeLocked()); } private int getSecureIntForUser(String key, int userId) { return Settings.Secure.getIntForUser(mMockResolver, key, -1, userId); } Loading