Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b7aed88 authored by Ryan Lin's avatar Ryan Lin Committed by Android (Google) Code Review
Browse files

Merge "Change MagnificationGestureHandler based on the magnificaotion mode"

parents fa228f3d 3a817a5f
Loading
Loading
Loading
Loading
+70 −8
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
            }
@@ -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();
@@ -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
+58 −0
Original line number Diff line number Diff line
@@ -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;
@@ -1744,6 +1766,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        scheduleUpdateClientsIfNeededLocked(userState);
        updateAccessibilityShortcutKeyTargetsLocked(userState);
        updateAccessibilityButtonTargetsLocked(userState);
        updateMagnificationModeChangeSettingsLocked();
    }

    private void updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState) {
@@ -1840,6 +1863,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        somethingChanged |= readAccessibilityShortcutKeySettingLocked(userState);
        somethingChanged |= readAccessibilityButtonSettingsLocked(userState);
        somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState);
        somethingChanged |= readMagnificationModeLocked(userState);
        return somethingChanged;
    }

@@ -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);
        }
@@ -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
@@ -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
+23 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;

@@ -159,6 +162,7 @@ class AccessibilityUserState {
        mIsAutoclickEnabled = false;
        mUserNonInteractiveUiTimeout = 0;
        mUserInteractiveUiTimeout = 0;
        mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
    }

    void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
@@ -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.
     */
+76 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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();
@@ -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;
    }
}
+16 −0
Original line number Diff line number Diff line
@@ -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;
@@ -116,6 +118,7 @@ public class AccessibilityUserStateTest {
        mUserState.setAutoclickEnabledLocked(true);
        mUserState.setUserNonInteractiveUiTimeoutLocked(30);
        mUserState.setUserInteractiveUiTimeoutLocked(30);
        mUserState.setMagnificationModeLocked(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);

        mUserState.onSwitchToAnotherUserLocked();

@@ -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
@@ -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);
    }