Merge "Support individual magnification mode for each display"

This commit is contained in:
Ryan Lin
2021-11-10 11:28:33 +00:00
committed by Android (Google) Code Review
15 changed files with 418 additions and 139 deletions

View File

@@ -28,7 +28,6 @@ import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.MathUtils;
import android.view.Gravity;
@@ -75,6 +74,7 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
private int mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
private final LayoutParams mParams;
private final SwitchListener mSwitchListener;
@VisibleForTesting
final Rect mDraggableWindowBounds = new Rect();
private boolean mIsVisible = false;
@@ -82,17 +82,29 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
private boolean mSingleTapDetected = false;
private boolean mToLeftScreenEdge = false;
MagnificationModeSwitch(@UiContext Context context) {
this(context, createView(context), new SfVsyncFrameCallbackProvider());
public interface SwitchListener {
/**
* Called when the switch is clicked to change the magnification mode.
* @param displayId the display id of the display to which the view's window has been
* attached
* @param magnificationMode the magnification mode
*/
void onSwitch(int displayId, int magnificationMode);
}
MagnificationModeSwitch(@UiContext Context context,
SwitchListener switchListener) {
this(context, createView(context), new SfVsyncFrameCallbackProvider(), switchListener);
}
@VisibleForTesting
MagnificationModeSwitch(Context context, @NonNull ImageView imageView,
SfVsyncFrameCallbackProvider sfVsyncFrameProvider) {
SfVsyncFrameCallbackProvider sfVsyncFrameProvider, SwitchListener switchListener) {
mContext = context;
mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
mWindowManager = mContext.getSystemService(WindowManager.class);
mSfVsyncFrameProvider = sfVsyncFrameProvider;
mSwitchListener = switchListener;
mParams = createLayoutParams(context);
mImageView = imageView;
mImageView.setOnTouchListener(this::onTouch);
@@ -364,11 +376,7 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
mMagnificationMode ^ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
mMagnificationMode = newMode;
mImageView.setImageResource(getIconResId(newMode));
Settings.Secure.putIntForUser(
mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
newMode,
UserHandle.USER_CURRENT);
mSwitchListener.onSwitch(mContext.getDisplayId(), newMode);
}
private void handleSingleTap() {

View File

@@ -18,6 +18,8 @@ package com.android.systemui.accessibility;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static com.android.systemui.accessibility.MagnificationModeSwitch.SwitchListener;
import android.annotation.MainThread;
import android.content.Context;
import android.hardware.display.DisplayManager;
@@ -27,21 +29,24 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.SysUISingleton;
/**
* A class to control {@link MagnificationModeSwitch}. It should show the button UI with following
* A class to control {@link MagnificationModeSwitch}. It shows the button UI with following
* conditions:
* <ol>
* <li> Both full-screen and window magnification mode are capable.</li>
* <li> The magnification scale is changed by a user.</li>
* <ol>
* The switch action will be handled by {@link #mSwitchListenerDelegate} which informs the system
* server about the changed mode.
*/
@SysUISingleton
public class ModeSwitchesController {
public class ModeSwitchesController implements SwitchListener {
private final DisplayIdIndexSupplier<MagnificationModeSwitch> mSwitchSupplier;
private SwitchListener mSwitchListenerDelegate;
public ModeSwitchesController(Context context) {
mSwitchSupplier = new SwitchSupplier(context,
context.getSystemService(DisplayManager.class));
context.getSystemService(DisplayManager.class), this::onSwitch);
}
@VisibleForTesting
@@ -50,8 +55,8 @@ public class ModeSwitchesController {
}
/**
* Shows a button that a user can click the button to switch magnification mode. And the
* button would be dismissed automatically after the button is displayed for a period of time.
* Shows a button that a user can click to switch magnification mode. And the button
* would be dismissed automatically after the button is displayed for a period of time.
*
* @param displayId The logical display id
* @param mode The magnification mode
@@ -93,24 +98,41 @@ public class ModeSwitchesController {
switchController -> switchController.onConfigurationChanged(configDiff));
}
@Override
public void onSwitch(int displayId, int magnificationMode) {
if (mSwitchListenerDelegate != null) {
mSwitchListenerDelegate.onSwitch(displayId, magnificationMode);
}
}
public void setSwitchListenerDelegate(SwitchListener switchListenerDelegate) {
mSwitchListenerDelegate = switchListenerDelegate;
}
private static class SwitchSupplier extends DisplayIdIndexSupplier<MagnificationModeSwitch> {
private final Context mContext;
private final SwitchListener mSwitchListener;
/**
* Supplies the switch for the given display.
*
* @param context Context
* @param displayManager DisplayManager
* @param switchListener The callback that will run when the switch is clicked
*/
SwitchSupplier(Context context, DisplayManager displayManager) {
SwitchSupplier(Context context, DisplayManager displayManager,
SwitchListener switchListener) {
super(displayManager);
mContext = context;
mSwitchListener = switchListener;
}
@Override
protected MagnificationModeSwitch createInstance(Display display) {
final Context uiContext = mContext.createWindowContext(display,
TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, /* options */ null);
return new MagnificationModeSwitch(uiContext);
return new MagnificationModeSwitch(uiContext, mSwitchListener);
}
}
}

View File

@@ -243,12 +243,15 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
mWindowMagnificationConnectionImpl = new WindowMagnificationConnectionImpl(this,
mHandler, mModeSwitchesController);
}
mModeSwitchesController.setSwitchListenerDelegate(
mWindowMagnificationConnectionImpl::onChangeMagnificationMode);
mAccessibilityManager.setWindowMagnificationConnection(
mWindowMagnificationConnectionImpl);
}
private void clearWindowMagnificationConnection() {
mAccessibilityManager.setWindowMagnificationConnection(null);
mModeSwitchesController.setSwitchListenerDelegate(null);
//TODO: destroy controllers.
}
}

View File

@@ -130,4 +130,14 @@ class WindowMagnificationConnectionImpl extends IWindowMagnificationConnection.S
}
}
}
void onChangeMagnificationMode(int displayId, int mode) {
if (mConnectionCallback != null) {
try {
mConnectionCallback.onChangeMagnificationMode(displayId, mode);
} catch (RemoteException e) {
Log.e(TAG, "Failed to inform changing magnification mode", e);
}
}
}
}

View File

@@ -55,10 +55,9 @@ import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.SparseIntArray;
import android.view.Choreographer;
import android.view.MotionEvent;
import android.view.View;
@@ -101,6 +100,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
private AccessibilityManager mAccessibilityManager;
@Mock
private SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
private SwitchListenerStub mSwitchListener;
private TestableWindowManager mWindowManager;
private ViewPropertyAnimator mViewPropertyAnimator;
private MagnificationModeSwitch mMagnificationModeSwitch;
@@ -112,6 +112,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
final WindowManager wm = mContext.getSystemService(WindowManager.class);
mSwitchListener = new SwitchListenerStub();
mWindowManager = spy(new TestableWindowManager(wm));
mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager);
@@ -130,7 +131,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
}).when(mSfVsyncFrameProvider).postFrameCallback(
any(Choreographer.FrameCallback.class));
mMagnificationModeSwitch = new MagnificationModeSwitch(mContext, mSpyImageView,
mSfVsyncFrameProvider);
mSfVsyncFrameProvider, mSwitchListener);
assertNotNull(mTouchListener);
}
@@ -326,8 +327,6 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
public void performDragging_showMagnificationButton_updateViewLayout() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
resetAndStubMockImageViewAndAnimator();
final int previousMode = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0, UserHandle.USER_CURRENT);
// Perform dragging
final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop() + 10;
@@ -345,7 +344,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
downTime, downTime, ACTION_UP, 100 + offset, 100));
assertModeUnchanged(previousMode);
assertModeUnchanged();
assertShowFadingAnimation(FADE_OUT_ALPHA);
}
@@ -353,8 +352,6 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
public void performSingleTapActionCanceled_showButtonAnimation() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
resetAndStubMockImageViewAndAnimator();
final int previousMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
final long downTime = SystemClock.uptimeMillis();
mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
@@ -363,7 +360,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
downTime, downTime, ACTION_CANCEL, 100, 100));
assertModeUnchanged(previousMode);
assertModeUnchanged();
assertShowFadingAnimation(FADE_OUT_ALPHA);
}
@@ -371,8 +368,6 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
public void performDraggingActionCanceled_showButtonAnimation() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
resetAndStubMockImageViewAndAnimator();
final int previousMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
// Perform dragging
final long downTime = SystemClock.uptimeMillis();
@@ -385,7 +380,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
downTime, downTime, ACTION_CANCEL, 100 + offset, 100));
assertModeUnchanged(previousMode);
assertModeUnchanged();
assertShowFadingAnimation(FADE_OUT_ALPHA);
}
@@ -529,10 +524,9 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
assertEquals(expectedY, mWindowManager.getLayoutParamsFromAttachedView().y);
}
private void assertModeUnchanged(int expectedMode) {
final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
assertEquals(expectedMode, actualMode);
private void assertModeUnchanged() {
assertEquals(SwitchListenerStub.MODE_INVALID,
mSwitchListener.getChangedMode(mContext.getDisplayId()));
}
private void assertShowFadingAnimation(float alpha) {
@@ -594,9 +588,8 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
verify(mSpyImageView).setImageResource(
getIconResId(expectedMode));
verify(mWindowManager).removeView(mSpyImageView);
final int actualMode = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0, UserHandle.USER_CURRENT);
assertEquals(expectedMode, actualMode);
final int changedMode = mSwitchListener.getChangedMode(mContext.getDisplayId());
assertEquals(expectedMode, changedMode);
}
private MotionEvent obtainMotionEvent(long downTime, long eventTime, int action, float x,
@@ -621,4 +614,20 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
assertEquals(expectedX, layoutParams.x);
assertEquals(expectedY, layoutParams.y);
}
private static class SwitchListenerStub implements MagnificationModeSwitch.SwitchListener {
private static final int MODE_INVALID = -1;
private final SparseIntArray mModes = new SparseIntArray();
@Override
public void onSwitch(int displayId, int magnificationMode) {
mModes.put(displayId, magnificationMode);
}
int getChangedMode(int displayId) {
return mModes.get(displayId, MODE_INVALID);
}
}
}

View File

@@ -22,27 +22,32 @@ import android.content.pm.ActivityInfo;
import android.hardware.display.DisplayManager;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Display;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
/** Tests the ModeSwitchesController. */
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class ModeSwitchesControllerTest extends SysuiTestCase {
private FakeSwitchSupplier mSupplier;
@Mock
private MagnificationModeSwitch mModeSwitch;
private ModeSwitchesController mModeSwitchesController;
@Mock
private MagnificationModeSwitch.SwitchListener mListener;
@Before
@@ -50,6 +55,13 @@ public class ModeSwitchesControllerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mSupplier = new FakeSwitchSupplier(mContext.getSystemService(DisplayManager.class));
mModeSwitchesController = new ModeSwitchesController(mSupplier);
mModeSwitchesController.setSwitchListenerDelegate(mListener);
mModeSwitch = Mockito.spy(new MagnificationModeSwitch(mContext, mModeSwitchesController));
}
@After
public void tearDown() {
mModeSwitchesController.removeButton(Display.DEFAULT_DISPLAY);
}
@Test
@@ -79,6 +91,18 @@ public class ModeSwitchesControllerTest extends SysuiTestCase {
verify(mModeSwitch).onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
}
@Test
public void testOnSwitchClick_showWindowModeButton_invokeListener() {
mModeSwitchesController.showButton(Display.DEFAULT_DISPLAY,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
mModeSwitch.onSingleTap();
verify(mListener).onSwitch(mContext.getDisplayId(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
}
private class FakeSwitchSupplier extends DisplayIdIndexSupplier<MagnificationModeSwitch> {
FakeSwitchSupplier(DisplayManager displayManager) {

View File

@@ -22,6 +22,8 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_M
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -99,17 +101,19 @@ public class WindowMagnificationTest extends SysuiTestCase {
}
@Test
public void requestWindowMagnificationConnection_setWindowMagnificationConnection() {
public void requestWindowMagnificationConnection_setConnectionAndListener() {
mCommandQueue.requestWindowMagnificationConnection(true);
waitForIdleSync();
verify(mAccessibilityManager).setWindowMagnificationConnection(any(
IWindowMagnificationConnection.class));
verify(mModeSwitchesController).setSwitchListenerDelegate(notNull());
mCommandQueue.requestWindowMagnificationConnection(false);
waitForIdleSync();
verify(mAccessibilityManager).setWindowMagnificationConnection(null);
verify(mAccessibilityManager).setWindowMagnificationConnection(isNull());
verify(mModeSwitchesController).setSwitchListenerDelegate(isNull());
}
@Test

View File

@@ -272,6 +272,27 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
return getUserStateLocked(mCurrentUserId);
}
/**
* Changes the magnification mode on the given display.
*
* @param displayId the logical display
* @param magnificationMode the target magnification mode
*/
public void changeMagnificationMode(int displayId, int magnificationMode) {
synchronized (mLock) {
if (displayId == Display.DEFAULT_DISPLAY) {
persistMagnificationModeSettingsLocked(magnificationMode);
} else {
final AccessibilityUserState userState = getCurrentUserStateLocked();
final int currentMode = userState.getMagnificationModeLocked(displayId);
if (magnificationMode != currentMode) {
userState.setMagnificationModeLocked(displayId, magnificationMode);
updateMagnificationModeChangeSettingsLocked(userState, displayId);
}
}
}
}
public static final class Lifecycle extends SystemService {
private final AccessibilityManagerService mService;
@@ -299,7 +320,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
SystemActionPerformer systemActionPerformer,
AccessibilityWindowManager a11yWindowManager,
AccessibilityDisplayListener a11yDisplayListener,
MagnificationController magnificationController) {
MagnificationController magnificationController,
@Nullable AccessibilityInputFilter inputFilter) {
mContext = context;
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
@@ -314,6 +336,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mA11yDisplayListener = a11yDisplayListener;
mMagnificationController = magnificationController;
mMagnificationProcessor = new MagnificationProcessor(mMagnificationController);
if (inputFilter != null) {
mInputFilter = inputFilter;
mHasInputFilter = true;
}
init();
}
@@ -1794,47 +1820,51 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
return relevantEventTypes;
}
private void updateMagnificationModeChangeSettingsLocked(AccessibilityUserState userState) {
private void updateMagnificationModeChangeSettingsLocked(AccessibilityUserState userState,
int displayId) {
if (userState.mUserId != mCurrentUserId) {
return;
}
// New mode is invalid, so ignore and restore it.
if (fallBackMagnificationModeSettingsLocked(userState)) {
if (fallBackMagnificationModeSettingsLocked(userState, displayId)) {
return;
}
mMagnificationController.transitionMagnificationModeLocked(
Display.DEFAULT_DISPLAY, userState.getMagnificationModeLocked(),
displayId, userState.getMagnificationModeLocked(displayId),
this::onMagnificationTransitionEndedLocked);
}
/**
* Called when the magnification mode transition is completed.
* Called when the magnification mode transition is completed. If the given display is default
* display, we also need to fall back the mode in user settings.
*/
void onMagnificationTransitionEndedLocked(boolean success) {
void onMagnificationTransitionEndedLocked(int displayId, boolean success) {
final AccessibilityUserState userState = getCurrentUserStateLocked();
final int previousMode = userState.getMagnificationModeLocked()
final int previousMode = userState.getMagnificationModeLocked(displayId)
^ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
if (!success && previousMode != 0) {
userState.setMagnificationModeLocked(previousMode);
persistMagnificationModeSettingLocked(previousMode);
userState.setMagnificationModeLocked(displayId, previousMode);
if (displayId == Display.DEFAULT_DISPLAY) {
persistMagnificationModeSettingsLocked(previousMode);
}
} else {
mMainHandler.sendMessage(obtainMessage(
AccessibilityManagerService::notifyRefreshMagnificationModeToInputFilter,
this));
this, displayId));
}
}
private void notifyRefreshMagnificationModeToInputFilter() {
private void notifyRefreshMagnificationModeToInputFilter(int displayId) {
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) {
if (display != null && display.getDisplayId() == displayId) {
mInputFilter.refreshMagnificationMode(display);
return;
}
}
}
@@ -2245,12 +2275,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
scheduleUpdateClientsIfNeededLocked(userState);
updateAccessibilityShortcutKeyTargetsLocked(userState);
updateAccessibilityButtonTargetsLocked(userState);
// Update the capabilities before the mode.
// Update the capabilities before the mode because we will check the current mode is
// invalid or not..
updateMagnificationCapabilitiesSettingsChangeLocked(userState);
updateMagnificationModeChangeSettingsLocked(userState);
updateMagnificationModeChangeSettingsForAllDisplaysLocked(userState);
updateFocusAppearanceDataLocked(userState);
}
private void updateMagnificationModeChangeSettingsForAllDisplaysLocked(
AccessibilityUserState userState) {
final ArrayList<Display> displays = getValidDisplayList();
for (int i = 0; i < displays.size(); i++) {
final int displayId = displays.get(i).getDisplayId();
updateMagnificationModeChangeSettingsLocked(userState, displayId);
}
}
private void updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState) {
// We observe windows for accessibility only if there is at least
// one bound service that can retrieve window content that specified
@@ -2348,7 +2388,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
somethingChanged |= readAccessibilityButtonTargetsLocked(userState);
somethingChanged |= readAccessibilityButtonTargetComponentLocked(userState);
somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState);
somethingChanged |= readMagnificationModeLocked(userState);
somethingChanged |= readMagnificationModeForDefaultDisplayLocked(userState);
somethingChanged |= readMagnificationCapabilitiesLocked(userState);
return somethingChanged;
}
@@ -3878,8 +3918,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|| mUserInteractiveUiTimeoutUri.equals(uri)) {
readUserRecommendedUiTimeoutSettingsLocked(userState);
} else if (mMagnificationModeUri.equals(uri)) {
if (readMagnificationModeLocked(userState)) {
updateMagnificationModeChangeSettingsLocked(userState);
if (readMagnificationModeForDefaultDisplayLocked(userState)) {
updateMagnificationModeChangeSettingsLocked(userState,
Display.DEFAULT_DISPLAY);
}
} else if (mMagnificationCapabilityUri.equals(uri)) {
if (readMagnificationCapabilitiesLocked(userState)) {
@@ -3892,8 +3933,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private void updateMagnificationCapabilitiesSettingsChangeLocked(
AccessibilityUserState userState) {
if (fallBackMagnificationModeSettingsLocked(userState)) {
updateMagnificationModeChangeSettingsLocked(userState);
final ArrayList<Display> displays = getValidDisplayList();
for (int i = 0; i < displays.size(); i++) {
final int displayId = displays.get(i).getDisplayId();
if (fallBackMagnificationModeSettingsLocked(userState, displayId)) {
updateMagnificationModeChangeSettingsLocked(userState, displayId);
}
}
updateWindowMagnificationConnectionIfNeeded(userState);
// Remove magnification button UI when the magnification capability is not all mode or
@@ -3902,7 +3947,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
|| userState.isShortcutMagnificationEnabledLocked())
|| userState.getMagnificationCapabilitiesLocked()
!= Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) {
final ArrayList<Display> displays = getValidDisplayList();
for (int i = 0; i < displays.size(); i++) {
final int displayId = displays.get(i).getDisplayId();
getWindowMagnificationMgr().removeMagnificationButton(displayId);
@@ -3910,18 +3955,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
private boolean fallBackMagnificationModeSettingsLocked(AccessibilityUserState userState) {
if (userState.isValidMagnificationModeLocked()) {
private boolean fallBackMagnificationModeSettingsLocked(AccessibilityUserState userState,
int displayId) {
if (userState.isValidMagnificationModeLocked(displayId)) {
return false;
}
Slog.w(LOG_TAG, "invalid magnification mode:" + userState.getMagnificationModeLocked());
Slog.w(LOG_TAG, "displayId " + displayId + ", invalid magnification mode:"
+ userState.getMagnificationModeLocked(displayId));
final int capabilities = userState.getMagnificationCapabilitiesLocked();
userState.setMagnificationModeLocked(capabilities);
persistMagnificationModeSettingLocked(capabilities);
userState.setMagnificationModeLocked(displayId, capabilities);
if (displayId == Display.DEFAULT_DISPLAY) {
persistMagnificationModeSettingsLocked(capabilities);
}
return true;
}
private void persistMagnificationModeSettingLocked(int mode) {
private void persistMagnificationModeSettingsLocked(int mode) {
BackgroundThread.getHandler().post(() -> {
final long identity = Binder.clearCallingIdentity();
try {
@@ -3933,7 +3982,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
});
}
//TODO: support multi-display.
/**
* Gets the magnification mode of the specified display.
*
@@ -3943,17 +3991,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*/
public int getMagnificationMode(int displayId) {
synchronized (mLock) {
return getCurrentUserStateLocked().getMagnificationModeLocked();
return getCurrentUserStateLocked().getMagnificationModeLocked(displayId);
}
}
private boolean readMagnificationModeLocked(AccessibilityUserState userState) {
// Only the value of the default display is from user settings because not each of displays has
// a unique id.
private boolean readMagnificationModeForDefaultDisplayLocked(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);
if (magnificationMode != userState.getMagnificationModeLocked(Display.DEFAULT_DISPLAY)) {
userState.setMagnificationModeLocked(Display.DEFAULT_DISPLAY, magnificationMode);
return true;
}
return false;

View File

@@ -23,6 +23,7 @@ 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.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static android.view.accessibility.AccessibilityManager.ShortcutType;
@@ -42,6 +43,7 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseIntArray;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;
@@ -122,8 +124,8 @@ class AccessibilityUserState {
/** {@code true} if the device config supports magnification area. */
private final boolean mSupportMagnificationArea;
// The magnification mode of default display.
private int mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
// The magnification modes on displays.
private final SparseIntArray mMagnificationModes = new SparseIntArray();
// The magnification capabilities used to know magnification mode could be switched.
private int mMagnificationCapabilities = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
@@ -141,12 +143,13 @@ class AccessibilityUserState {
@SoftKeyboardShowMode
private int mSoftKeyboardShowMode = SHOW_MODE_AUTO;
boolean isValidMagnificationModeLocked() {
boolean isValidMagnificationModeLocked(int displayId) {
final int mode = getMagnificationModeLocked(displayId);
if (!mSupportMagnificationArea
&& mMagnificationMode == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
&& mode == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
return false;
}
return (mMagnificationCapabilities & mMagnificationMode) != 0;
return (mMagnificationCapabilities & mode) != 0;
}
interface ServiceInfoChangeListener {
@@ -203,7 +206,7 @@ class AccessibilityUserState {
mIsAutoclickEnabled = false;
mUserNonInteractiveUiTimeout = 0;
mUserInteractiveUiTimeout = 0;
mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
mMagnificationModes.clear();
mFocusStrokeWidth = mFocusStrokeWidthDefaultValue;
mFocusColor = mFocusColorDefaultValue;
}
@@ -500,7 +503,7 @@ class AccessibilityUserState {
pw.append(", nonInteractiveUiTimeout=").append(String.valueOf(mNonInteractiveUiTimeout));
pw.append(", interactiveUiTimeout=").append(String.valueOf(mInteractiveUiTimeout));
pw.append(", installedServiceCount=").append(String.valueOf(mInstalledServices.size()));
pw.append(", magnificationMode=").append(String.valueOf(mMagnificationMode));
pw.append(", magnificationModes=").append(String.valueOf(mMagnificationModes));
pw.append(", magnificationCapabilities=")
.append(String.valueOf(mMagnificationCapabilities));
pw.append("}");
@@ -635,14 +638,19 @@ class AccessibilityUserState {
}
/**
* Gets the magnification mode of default display.
* Gets the magnification mode for the given display.
* @return magnification mode
*
* @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
* @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
*/
public int getMagnificationModeLocked() {
return mMagnificationMode;
public int getMagnificationModeLocked(int displayId) {
int mode = mMagnificationModes.get(displayId, ACCESSIBILITY_MAGNIFICATION_MODE_NONE);
if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_NONE) {
mode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
setMagnificationModeLocked(displayId, mode);
}
return mode;
}
@@ -671,11 +679,13 @@ class AccessibilityUserState {
}
/**
* Sets the magnification mode of default display.
* Sets the magnification mode to the given display.
*
* @param displayId The display id.
* @param mode The magnification mode.
*/
public void setMagnificationModeLocked(int mode) {
mMagnificationMode = mode;
public void setMagnificationModeLocked(int displayId, int mode) {
mMagnificationModes.put(displayId, mode);
}
/**

View File

@@ -208,8 +208,8 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
}
mPromptController.onDestroy();
// Check if need to reset when MagnificationGestureHandler is the last magnifying service.
mFullScreenMagnificationController.resetAllIfNeeded(
AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
mFullScreenMagnificationController.resetIfNeeded(
mDisplayId, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
clearAndTransitionToStateDetecting();
}

View File

@@ -92,14 +92,16 @@ public class MagnificationController implements WindowMagnificationManager.Callb
private long mFullScreenModeEnabledTime = 0;
/**
* A callback to inform the magnification transition result.
* A callback to inform the magnification transition result on the given display.
*/
public interface TransitionCallBack {
/**
* Invoked when the transition ends.
*
* @param displayId The display id.
* @param success {@code true} if the transition success.
*/
void onResult(boolean success);
void onResult(int displayId, boolean success);
}
public MagnificationController(AccessibilityManagerService ams, Object lock,
@@ -179,7 +181,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
final DisableMagnificationCallback animationCallback =
getDisableMagnificationEndRunnableLocked(displayId);
if (magnificationCenter == null && animationCallback == null) {
transitionCallBack.onResult(true);
transitionCallBack.onResult(displayId, true);
return;
}
@@ -195,7 +197,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
if (magnificationCenter == null) {
Slog.w(TAG, "Invalid center, ignore it");
transitionCallBack.onResult(true);
transitionCallBack.onResult(displayId, true);
return;
}
final FullScreenMagnificationController screenMagnificationController =
@@ -251,6 +253,11 @@ public class MagnificationController implements WindowMagnificationManager.Callb
updateMagnificationButton(displayId, ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
}
@Override
public void onChangeMagnificationMode(int displayId, int magnificationMode) {
mAms.changeMagnificationMode(displayId, magnificationMode);
}
private void disableFullScreenMagnificationIfNeeded(int displayId) {
final FullScreenMagnificationController fullScreenMagnificationController =
getFullScreenMagnificationController();
@@ -514,7 +521,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
applyMagnificationModeLocked(mTargetMode);
}
updateMagnificationButton(mDisplayId, mTargetMode);
mTransitionCallBack.onResult(success);
mTransitionCallBack.onResult(mDisplayId, success);
}
}
@@ -539,7 +546,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
setExpiredAndRemoveFromListLocked();
applyMagnificationModeLocked(mCurrentMode);
updateMagnificationButton(mDisplayId, mCurrentMode);
mTransitionCallBack.onResult(true);
mTransitionCallBack.onResult(mDisplayId, true);
}
}

View File

@@ -106,6 +106,15 @@ public class WindowMagnificationManager implements
* @param activated {@code true} if the magnification is activated, otherwise {@code false}.
*/
void onWindowMagnificationActivationState(int displayId, boolean activated);
/**
* Called from {@link IWindowMagnificationConnection} to request changing the magnification
* mode on the given display.
*
* @param displayId the logical display id
* @param magnificationMode the target magnification mode
*/
void onChangeMagnificationMode(int displayId, int magnificationMode);
}
private final Callback mCallback;
@@ -535,7 +544,7 @@ public class WindowMagnificationManager implements
FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK,
"displayId=" + displayId + ";mode=" + magnificationMode);
}
//TODO: Uses this method to change the magnification mode on non-default display.
mCallback.onChangeMagnificationMode(displayId, magnificationMode);
}
@Override

View File

@@ -16,13 +16,22 @@
package com.android.server.accessibility;
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;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -38,17 +47,23 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.graphics.drawable.Icon;
import android.hardware.display.DisplayManagerGlobal;
import android.os.IBinder;
import android.provider.Settings;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.TestableContext;
import android.view.Display;
import android.view.DisplayAdjustments;
import android.view.DisplayInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.TestUtils;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityManagerService.AccessibilityDisplayListener;
import com.android.server.accessibility.magnification.FullScreenMagnificationController;
import com.android.server.accessibility.magnification.MagnificationController;
import com.android.server.accessibility.magnification.WindowMagnificationManager;
import com.android.server.accessibility.test.MessageCapturingHandler;
@@ -58,10 +73,16 @@ import com.android.server.wm.WindowManagerInternal;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
/**
* APCT tests for {@link AccessibilityManagerService}.
*/
@@ -72,7 +93,8 @@ public class AccessibilityManagerServiceTest {
private static final String INTENT_ACTION = "TESTACTION";
private static final String DESCRIPTION = "description";
private static final PendingIntent TEST_PENDING_INTENT = PendingIntent.getBroadcast(
InstrumentationRegistry.getTargetContext(), 0, new Intent(INTENT_ACTION), PendingIntent.FLAG_MUTABLE_UNAUDITED);
InstrumentationRegistry.getTargetContext(), 0, new Intent(INTENT_ACTION),
PendingIntent.FLAG_MUTABLE_UNAUDITED);
private static final RemoteAction TEST_ACTION = new RemoteAction(
Icon.createWithContentUri("content://test"),
LABEL,
@@ -81,11 +103,12 @@ public class AccessibilityManagerServiceTest {
private static final AccessibilityAction NEW_ACCESSIBILITY_ACTION =
new AccessibilityAction(ACTION_ID, LABEL);
private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY + 1;
static final ComponentName COMPONENT_NAME = new ComponentName(
"com.android.server.accessibility", "AccessibilityManagerServiceTest");
static final int SERVICE_ID = 42;
@Mock private Context mMockContext;
@Mock private AccessibilityServiceInfo mMockServiceInfo;
@Mock private ResolveInfo mMockResolveInfo;
@Mock private AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
@@ -102,12 +125,15 @@ public class AccessibilityManagerServiceTest {
@Mock private IAccessibilityServiceClient mMockServiceClient;
@Mock private WindowMagnificationManager mMockWindowMagnificationMgr;
@Mock private MagnificationController mMockMagnificationController;
@Mock private Resources mMockResources;
@Mock private FullScreenMagnificationController mMockFullScreenMagnificationController;
private AccessibilityUserState mUserState;
@Rule
public final TestableContext mTestableContext = new TestableContext(
getInstrumentation().getTargetContext(), null);
private MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
private AccessibilityServiceConnection mAccessibilityServiceConnection;
private AccessibilityInputFilter mInputFilter;
private AccessibilityManagerService mA11yms;
@Before
@@ -122,43 +148,54 @@ public class AccessibilityManagerServiceTest {
ActivityTaskManagerInternal.class, mMockActivityTaskManagerInternal);
LocalServices.addService(
UserManagerInternal.class, mMockUserManagerInternal);
mInputFilter = Mockito.mock(FakeInputFilter.class);
when(mMockMagnificationController.getWindowMagnificationMgr()).thenReturn(
mMockWindowMagnificationMgr);
when(mMockMagnificationController.getFullScreenMagnificationController()).thenReturn(
mMockFullScreenMagnificationController);
when(mMockWindowManagerService.getAccessibilityController()).thenReturn(
mMockA11yController);
when(mMockA11yController.isAccessibilityTracingEnabled()).thenReturn(false);
when(mMockUserManagerInternal.isUserUnlockingOrUnlocked(anyInt())).thenReturn(true);
final ArrayList<Display> displays = new ArrayList<>();
final Display defaultDisplay = new Display(DisplayManagerGlobal.getInstance(),
Display.DEFAULT_DISPLAY, new DisplayInfo(),
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
final Display testDisplay = new Display(DisplayManagerGlobal.getInstance(), TEST_DISPLAY,
new DisplayInfo(), DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
displays.add(defaultDisplay);
displays.add(testDisplay);
when(mMockA11yDisplayListener.getValidDisplayList()).thenReturn(displays);
mA11yms = new AccessibilityManagerService(
InstrumentationRegistry.getContext(),
mMockPackageManager,
mMockSecurityPolicy,
mMockSystemActionPerformer,
mMockA11yWindowManager,
mMockA11yDisplayListener,
mMockMagnificationController);
mTestableContext,
mMockPackageManager,
mMockSecurityPolicy,
mMockSystemActionPerformer,
mMockA11yWindowManager,
mMockA11yDisplayListener,
mMockMagnificationController,
mInputFilter);
mMockResources = mock(Resources.class);
when(mMockContext.getResources()).thenReturn(mMockResources);
mUserState = new AccessibilityUserState(
mA11yms.getCurrentUserIdLocked(), mMockContext, mA11yms);
mA11yms.mUserStates.put(mA11yms.getCurrentUserIdLocked(), mUserState);
final AccessibilityUserState userState = new AccessibilityUserState(
mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
mA11yms.mUserStates.put(mA11yms.getCurrentUserIdLocked(), userState);
}
private void setupAccessibilityServiceConnection() {
when(mMockContext.getSystemService(Context.DISPLAY_SERVICE)).thenReturn(
InstrumentationRegistry.getContext().getSystemService(
Context.DISPLAY_SERVICE));
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
when(mMockServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
mMockResolveInfo.serviceInfo = mock(ServiceInfo.class);
mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
when(mMockBinder.queryLocalInterface(any())).thenReturn(mMockServiceClient);
mTestableContext.addMockService(COMPONENT_NAME, mMockBinder);
mAccessibilityServiceConnection = new AccessibilityServiceConnection(
mUserState,
mMockContext,
userState,
mTestableContext,
COMPONENT_NAME,
mMockServiceInfo,
SERVICE_ID,
@@ -172,7 +209,6 @@ public class AccessibilityManagerServiceTest {
mMockA11yWindowManager,
mMockActivityTaskManagerInternal);
mAccessibilityServiceConnection.bindLocked();
mAccessibilityServiceConnection.onServiceConnected(COMPONENT_NAME, mMockBinder);
}
@SmallTest
@@ -220,7 +256,10 @@ public class AccessibilityManagerServiceTest {
@Test
public void testOnSystemActionsChanged() throws Exception {
setupAccessibilityServiceConnection();
mA11yms.notifySystemActionsChangedLocked(mUserState);
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
mA11yms.notifySystemActionsChangedLocked(userState);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
verify(mMockServiceClient).onSystemActionsChanged();
}
@@ -228,24 +267,89 @@ public class AccessibilityManagerServiceTest {
@SmallTest
@Test
public void testOnMagnificationTransitionFailed_capabilitiesIsAll_fallBackToPreviousMode() {
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
userState.setMagnificationCapabilitiesLocked(ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
userState.setMagnificationModeLocked(Display.DEFAULT_DISPLAY,
ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
);
mA11yms.onMagnificationTransitionEndedLocked(Display.DEFAULT_DISPLAY, false);
Assert.assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW,
userState.getMagnificationModeLocked(Display.DEFAULT_DISPLAY));
}
@SmallTest
@Test
public void testOnMagnificationTransitionSuccess_capabilitiesIsAll_inputFilterRefreshMode() {
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
userState.setMagnificationCapabilitiesLocked(
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
userState.setMagnificationModeLocked(
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
userState.setMagnificationModeLocked(Display.DEFAULT_DISPLAY,
ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
);
mA11yms.onMagnificationTransitionEndedLocked(false);
mA11yms.onMagnificationTransitionEndedLocked(Display.DEFAULT_DISPLAY, true);
Assert.assertEquals(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW,
userState.getMagnificationModeLocked());
ArgumentCaptor<Display> displayCaptor = ArgumentCaptor.forClass(Display.class);
verify(mInputFilter, timeout(100)).refreshMagnificationMode(displayCaptor.capture());
Assert.assertEquals(Display.DEFAULT_DISPLAY, displayCaptor.getValue().getDisplayId());
}
@SmallTest
@Test
public void testChangeMagnificationModeOnDefaultDisplay_capabilitiesIsAll_persistChangedMode()
throws Exception {
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
userState.setMagnificationCapabilitiesLocked(
ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
userState.setMagnificationModeLocked(Display.DEFAULT_DISPLAY,
ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
);
mA11yms.changeMagnificationMode(Display.DEFAULT_DISPLAY,
ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
TestUtils.waitUntil("magnification mode " + ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
+ " is not persisted in setting", 1,
() -> {
final int userMode = Settings.Secure.getIntForUser(
mTestableContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
ACCESSIBILITY_MAGNIFICATION_MODE_NONE,
mA11yms.getCurrentUserIdLocked());
return userMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
});
}
@SmallTest
@Test
public void testChangeMagnificationModeOnTestDisplay_capabilitiesIsAll_transitMode() {
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
userState.setMagnificationCapabilitiesLocked(
ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
userState.setMagnificationModeLocked(TEST_DISPLAY,
ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
);
mA11yms.changeMagnificationMode(TEST_DISPLAY,
ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
verify(mMockMagnificationController).transitionMagnificationModeLocked(eq(TEST_DISPLAY),
eq(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW), ArgumentMatchers.isNotNull());
}
@SmallTest
@Test
public void testOnClientChange_magnificationEnabledAndCapabilityAll_requestConnection() {
mUserState.mAccessibilityShortcutKeyTargets.add(MAGNIFICATION_CONTROLLER_NAME);
mUserState.setMagnificationCapabilitiesLocked(
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
userState.mAccessibilityShortcutKeyTargets.add(MAGNIFICATION_CONTROLLER_NAME);
userState.setMagnificationCapabilitiesLocked(
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
// Invokes client change to trigger onUserStateChanged.
@@ -265,4 +369,11 @@ public class AccessibilityManagerServiceTest {
verify(mMockWindowMagnificationMgr).requestConnection(true);
}
public static class FakeInputFilter extends AccessibilityInputFilter {
FakeInputFilter(Context context,
AccessibilityManagerService service) {
super(context, service);
}
}
}

View File

@@ -48,6 +48,7 @@ import android.provider.Settings;
import android.test.mock.MockContentResolver;
import android.testing.DexmakerShareClassLoaderRule;
import android.util.ArraySet;
import android.view.Display;
import androidx.test.InstrumentationRegistry;
@@ -79,6 +80,8 @@ public class AccessibilityUserStateTest {
private static final int USER_ID = 42;
private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
// Mock package-private class AccessibilityServiceConnection
@Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
new DexmakerShareClassLoaderRule();
@@ -143,7 +146,8 @@ public class AccessibilityUserStateTest {
mUserState.setAutoclickEnabledLocked(true);
mUserState.setUserNonInteractiveUiTimeoutLocked(30);
mUserState.setUserInteractiveUiTimeoutLocked(30);
mUserState.setMagnificationModeLocked(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
mUserState.setMagnificationModeLocked(TEST_DISPLAY,
ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
mUserState.setFocusAppearanceLocked(20, Color.BLUE);
mUserState.onSwitchToAnotherUserLocked();
@@ -165,7 +169,7 @@ public class AccessibilityUserStateTest {
assertEquals(0, mUserState.getUserNonInteractiveUiTimeoutLocked());
assertEquals(0, mUserState.getUserInteractiveUiTimeoutLocked());
assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN,
mUserState.getMagnificationModeLocked());
mUserState.getMagnificationModeLocked(TEST_DISPLAY));
assertEquals(mFocusStrokeWidthDefaultValue, mUserState.getFocusStrokeWidthLocked());
assertEquals(mFocusColorDefaultValue, mUserState.getFocusColorLocked());
}
@@ -360,12 +364,13 @@ public class AccessibilityUserStateTest {
@Test
public void setWindowMagnificationMode_returnExpectedMagnificationMode() {
assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN,
mUserState.getMagnificationModeLocked());
mUserState.getMagnificationModeLocked(TEST_DISPLAY));
mUserState.setMagnificationModeLocked(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
mUserState.setMagnificationModeLocked(TEST_DISPLAY,
ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW,
mUserState.getMagnificationModeLocked());
mUserState.getMagnificationModeLocked(TEST_DISPLAY));
}
@Test

View File

@@ -150,7 +150,7 @@ public class MagnificationControllerTest {
MODE_WINDOW,
mTransitionCallBack);
verify(mTransitionCallBack).onResult(true);
verify(mTransitionCallBack).onResult(TEST_DISPLAY, true);
verify(mScreenMagnificationController, never()).reset(anyInt(),
any(MagnificationAnimationCallback.class));
verify(mMockConnection.getConnection(), never()).enableWindowMagnification(anyInt(),
@@ -171,7 +171,7 @@ public class MagnificationControllerTest {
mCallbackArgumentCaptor.capture());
mCallbackArgumentCaptor.getValue().onResult(true);
mMockConnection.invokeCallbacks();
verify(mTransitionCallBack).onResult(true);
verify(mTransitionCallBack).onResult(TEST_DISPLAY, true);
assertEquals(MAGNIFIED_CENTER_X, mWindowMagnificationManager.getCenterX(TEST_DISPLAY), 0);
assertEquals(MAGNIFIED_CENTER_Y, mWindowMagnificationManager.getCenterY(TEST_DISPLAY), 0);
}
@@ -189,7 +189,7 @@ public class MagnificationControllerTest {
mTransitionCallBack);
mMockConnection.invokeCallbacks();
verify(mTransitionCallBack).onResult(true);
verify(mTransitionCallBack).onResult(TEST_DISPLAY, true);
assertEquals(MAGNIFIED_CENTER_X, mWindowMagnificationManager.getCenterX(TEST_DISPLAY), 0);
assertEquals(MAGNIFIED_CENTER_Y, mWindowMagnificationManager.getCenterY(TEST_DISPLAY), 0);
}
@@ -225,7 +225,7 @@ public class MagnificationControllerTest {
verify(mScreenMagnificationController).setScaleAndCenter(TEST_DISPLAY,
DEFAULT_SCALE, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y,
true, MAGNIFICATION_GESTURE_HANDLER_ID);
verify(mTransitionCallBack).onResult(true);
verify(mTransitionCallBack).onResult(TEST_DISPLAY, true);
}
@Test
@@ -245,7 +245,7 @@ public class MagnificationControllerTest {
verify(mScreenMagnificationController).setScaleAndCenter(TEST_DISPLAY, DEFAULT_SCALE,
magnificationBounds.exactCenterX(), magnificationBounds.exactCenterY(), true,
MAGNIFICATION_GESTURE_HANDLER_ID);
verify(mTransitionCallBack).onResult(true);
verify(mTransitionCallBack).onResult(TEST_DISPLAY, true);
}
@Test
@@ -265,7 +265,7 @@ public class MagnificationControllerTest {
0);
assertEquals(MAGNIFIED_CENTER_Y, mScreenMagnificationController.getCenterY(TEST_DISPLAY),
0);
verify(mTransitionCallBack).onResult(true);
verify(mTransitionCallBack).onResult(TEST_DISPLAY, true);
}
@Test
@@ -285,7 +285,7 @@ public class MagnificationControllerTest {
verify(mScreenMagnificationController, never()).setScaleAndCenter(TEST_DISPLAY,
DEFAULT_SCALE, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y,
true, MAGNIFICATION_GESTURE_HANDLER_ID);
verify(mTransitionCallBack).onResult(false);
verify(mTransitionCallBack).onResult(TEST_DISPLAY, false);
}
@Test
@@ -595,6 +595,13 @@ public class MagnificationControllerTest {
verify(mScaleProvider).onUserRemoved(SECOND_USER_ID);
}
@Test
public void onChangeMagnificationMode_delegateToService() {
mMagnificationController.onChangeMagnificationMode(TEST_DISPLAY, MODE_WINDOW);
verify(mService).changeMagnificationMode(TEST_DISPLAY, MODE_WINDOW);
}
private void setMagnificationEnabled(int mode) throws RemoteException {
setMagnificationEnabled(mode, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
}