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

Commit 21a62f3c authored by Daniel Hsieh's avatar Daniel Hsieh
Browse files

Support following typing foucs in window mode [1/n].

There are 2 milestones in this feature.
1. Refactor the callbacks for Accessibility in WindowManagerInternal.
2. Implement this feature in such new architecture.

This CL is for the 1st milestone.

The goal of refactor:
When the window manager invokes callbacks which are related to
contextual changes affecting the screen magnification feature, it will
be handle by the MagnificationController first now. Then, it will
dispatch the events to the activated magnification controller such as
FullScreenMagnificationController or WindowMagnificationManager.

We use delegate design pattern to make MagnificationController as proxy.
It will assign a specific delegate when the activated controller is changed.
Then, it will dispatch the events from window manager to activated
magnification controller. Therefore, the activated magnification
controller will handle this event.

For now, we introduce WindowManagerEventDispatcher in
AccessibilityControllerInternalImpl to pass the callback events to
MagnificationController. However, AccessibilityControllerInternalImpl
would be refactored since it should have no nested class relation with
AccessibilityController.

Bug: 194668976
Test: atest FullScreenMagnificationControllerTest
	atest WindowMagnificationManagerTest
	atest MagnificationControllerTest
	atest CtsAccessibilityServiceTestCases
Change-Id: Ic4d87c48a15b9179afeda48132635adc8e86107c
parent 0ee1df68
Loading
Loading
Loading
Loading
+24 −1
Original line number Diff line number Diff line
@@ -63,7 +63,8 @@ import java.util.Locale;
 * magnification region. If a value is out of bounds, it will be adjusted to guarantee these
 * constraints.
 */
public class FullScreenMagnificationController {
public class FullScreenMagnificationController implements
        WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks {
    private static final boolean DEBUG = false;
    private static final String LOG_TAG = "FullScreenMagnificationController";

@@ -85,6 +86,8 @@ public class FullScreenMagnificationController {
    @GuardedBy("mLock")
    private final SparseArray<DisplayMagnification> mDisplays = new SparseArray<>(0);

    private final Rect mTempRect = new Rect();

    /**
     * This class implements {@link WindowManagerInternal.MagnificationCallbacks} and holds
     * magnification information per display.
@@ -727,6 +730,26 @@ public class FullScreenMagnificationController {
        }
    }

    @Override
    public void onRectangleOnScreenRequested(int displayId, int left, int top, int right,
            int bottom) {
        synchronized (mLock) {
            final DisplayMagnification display = mDisplays.get(displayId);
            if (display == null) {
                return;
            }
            if (!display.isMagnifying()) {
                return;
            }
            final Rect magnifiedRegionBounds = mTempRect;
            display.getMagnifiedFrameInContentCoordsLocked(magnifiedRegionBounds);
            if (magnifiedRegionBounds.contains(left, top, right, bottom)) {
                return;
            }
            display.onRectangleOnScreenRequested(left, top, right, bottom);
        }
    }

    /**
     * Remove the display magnification with given id.
     *
+46 −5
Original line number Diff line number Diff line
@@ -40,7 +40,9 @@ import android.view.accessibility.MagnificationAnimationCallback;
import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.wm.WindowManagerInternal;

/**
 * Handles all magnification controllers initialization, generic interactions,
@@ -68,7 +70,8 @@ import com.android.server.accessibility.AccessibilityManagerService;
 */
public class MagnificationController implements WindowMagnificationManager.Callback,
        MagnificationGestureHandler.Callback,
        FullScreenMagnificationController.MagnificationInfoChangedCallback {
        FullScreenMagnificationController.MagnificationInfoChangedCallback,
        WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks {

    private static final boolean DEBUG = false;
    private static final String TAG = "MagnificationController";
@@ -96,6 +99,11 @@ public class MagnificationController implements WindowMagnificationManager.Callb
    private long mWindowModeEnabledTime = 0;
    private long mFullScreenModeEnabledTime = 0;

    @GuardedBy("mLock")
    @Nullable
    private WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks
            mAccessibilityCallbacksDelegate;

    /**
     * A callback to inform the magnification transition result on the given display.
     */
@@ -115,6 +123,8 @@ public class MagnificationController implements WindowMagnificationManager.Callb
        mLock = lock;
        mContext = context;
        mScaleProvider = scaleProvider;
        LocalServices.getService(WindowManagerInternal.class)
                .getAccessibilityController().setUiChangesForAccessibilityCallbacks(this);
    }

    @VisibleForTesting
@@ -292,6 +302,37 @@ public class MagnificationController implements WindowMagnificationManager.Callb
        return false;
    }

    @GuardedBy("mLock")
    private void setActivatedModeAndSwitchDelegate(int mode) {
        mActivatedMode = mode;
        assignMagnificationWindowManagerDelegateByMode(mode);
    }

    private void assignMagnificationWindowManagerDelegateByMode(int mode) {
        synchronized (mLock) {
            if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) {
                mAccessibilityCallbacksDelegate = getFullScreenMagnificationController();
            } else if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
                mAccessibilityCallbacksDelegate = getWindowMagnificationMgr();
            } else {
                mAccessibilityCallbacksDelegate = null;
            }
        }
    }

    @Override
    public void onRectangleOnScreenRequested(int displayId, int left, int top, int right,
            int bottom) {
        WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks
                delegate;
        synchronized (mLock) {
            delegate = mAccessibilityCallbacksDelegate;
        }
        if (delegate != null) {
            delegate.onRectangleOnScreenRequested(displayId, left, top, right, bottom);
        }
    }

    @Override
    public void onRequestMagnificationSpec(int displayId, int serviceId) {
        final WindowMagnificationManager windowMagnificationManager;
@@ -314,7 +355,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
            mWindowModeEnabledTime = SystemClock.uptimeMillis();

            synchronized (mLock) {
                mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
                setActivatedModeAndSwitchDelegate(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
                mLastActivatedMode = mActivatedMode;
            }
            logMagnificationModeWithImeOnIfNeeded();
@@ -324,7 +365,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
                    SystemClock.uptimeMillis() - mWindowModeEnabledTime);

            synchronized (mLock) {
                mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
                setActivatedModeAndSwitchDelegate(ACCESSIBILITY_MAGNIFICATION_MODE_NONE);
            }
        }
        updateMagnificationButton(displayId, ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
@@ -353,7 +394,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
            mFullScreenModeEnabledTime = SystemClock.uptimeMillis();

            synchronized (mLock) {
                mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
                setActivatedModeAndSwitchDelegate(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
                mLastActivatedMode = mActivatedMode;
            }
            logMagnificationModeWithImeOnIfNeeded();
@@ -363,7 +404,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
                    SystemClock.uptimeMillis() - mFullScreenModeEnabledTime);

            synchronized (mLock) {
                mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
                setActivatedModeAndSwitchDelegate(ACCESSIBILITY_MAGNIFICATION_MODE_NONE);
            }
        }
        updateMagnificationButton(displayId, ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+10 −1
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.WindowManagerInternal;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -57,7 +58,8 @@ import java.lang.annotation.RetentionPolicy;
 * {@link MagnificationScaleProvider#constrainScale(float)}
 */
public class WindowMagnificationManager implements
        PanningScalingHandler.MagnificationDelegate {
        PanningScalingHandler.MagnificationDelegate,
        WindowManagerInternal.AccessibilityControllerInternal.UiChangesForAccessibilityCallbacks {

    private static final boolean DBG = false;

@@ -263,6 +265,13 @@ public class WindowMagnificationManager implements
        }
    }

    @Override
    public void onRectangleOnScreenRequested(int displayId, int left, int top, int right,
            int bottom) {
        // TODO(b/194668976): We will implement following typing focus in window mode after
        //  our refactor.
    }

    @Override
    public boolean processScroll(int displayId, float distanceX, float distanceY) {
        moveWindowMagnification(displayId, -distanceX, -distanceY);
+89 −51
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ import android.view.animation.Interpolator;
import com.android.internal.R;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.TraceBuffer;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal;
@@ -277,20 +278,6 @@ final class AccessibilityController {
        }
    }

    void onRectangleOnScreenRequested(int displayId, Rect rectangle) {
        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
            mAccessibilityTracing.logTrace(
                    TAG + ".onRectangleOnScreenRequested",
                    FLAGS_MAGNIFICATION_CALLBACK,
                    "displayId=" + displayId + "; rectangle={" + rectangle + "}");
        }
        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
        if (displayMagnifier != null) {
            displayMagnifier.onRectangleOnScreenRequested(rectangle);
        }
        // Not relevant for the window observer.
    }

    void onWindowLayersChanged(int displayId) {
        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
                | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
@@ -634,31 +621,6 @@ final class AccessibilityController {
            return mForceShowMagnifiableBounds;
        }

        void onRectangleOnScreenRequested(Rect rectangle) {
            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
                mAccessibilityTracing.logTrace(LOG_TAG + ".onRectangleOnScreenRequested",
                        FLAGS_MAGNIFICATION_CALLBACK, "rectangle={" + rectangle + "}");
            }
            if (DEBUG_RECTANGLE_REQUESTED) {
                Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
            }
            if (!mMagnifedViewport.isMagnifying()) {
                return;
            }
            Rect magnifiedRegionBounds = mTempRect2;
            mMagnifedViewport.getMagnifiedFrameInContentCoords(magnifiedRegionBounds);
            if (magnifiedRegionBounds.contains(rectangle)) {
                return;
            }
            SomeArgs args = SomeArgs.obtain();
            args.argi1 = rectangle.left;
            args.argi2 = rectangle.top;
            args.argi3 = rectangle.right;
            args.argi4 = rectangle.bottom;
            mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED,
                    args).sendToTarget();
        }

        void onWindowLayersChanged() {
            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
                mAccessibilityTracing.logTrace(
@@ -1352,7 +1314,6 @@ final class AccessibilityController {

        private class MyHandler extends Handler {
            public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1;
            public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
            public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
            public static final int MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED = 4;
            public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
@@ -1372,16 +1333,6 @@ final class AccessibilityController {
                        magnifiedBounds.recycle();
                    } break;

                    case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
                        SomeArgs args = (SomeArgs) message.obj;
                        final int left = args.argi1;
                        final int top = args.argi2;
                        final int right = args.argi3;
                        final int bottom = args.argi4;
                        mCallbacks.onRectangleOnScreenRequested(left, top, right, bottom);
                        args.recycle();
                    } break;

                    case MESSAGE_NOTIFY_USER_CONTEXT_CHANGED: {
                        mCallbacks.onUserContextChanged();
                    } break;
@@ -1902,7 +1853,7 @@ final class AccessibilityController {
        }
    }

    private static final class AccessibilityControllerInternalImpl
    static final class AccessibilityControllerInternalImpl
            implements AccessibilityControllerInternal {

        private static AccessibilityControllerInternalImpl sInstance;
@@ -1917,8 +1868,11 @@ final class AccessibilityController {

        private final AccessibilityTracing mTracing;
        private volatile long mEnabledTracingFlags;
        private UiChangesForAccessibilityCallbacksDispatcher mCallbacksDispatcher;
        private final Looper mLooper;

        private AccessibilityControllerInternalImpl(WindowManagerService service) {
            mLooper = service.mH.getLooper();
            mTracing = AccessibilityTracing.getInstance(service);
            mEnabledTracingFlags = 0L;
        }
@@ -1972,6 +1926,90 @@ final class AccessibilityController {
            mTracing.logState(where, loggingTypes, callingParams, a11yDump, callingUid, callStack,
                    timeStamp, processId, threadId, ignoreStackEntries);
        }

        @Override
        public void setUiChangesForAccessibilityCallbacks(
                UiChangesForAccessibilityCallbacks callbacks) {
            if (isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
                logTrace(
                        TAG + ".setAccessibilityWindowManagerCallbacks",
                        FLAGS_MAGNIFICATION_CALLBACK,
                        "callbacks={" + callbacks + "}");
            }
            if (callbacks != null) {
                if (mCallbacksDispatcher != null) {
                    throw new IllegalStateException("Accessibility window manager callback already "
                            + "set!");
                }
                mCallbacksDispatcher =
                        new UiChangesForAccessibilityCallbacksDispatcher(this, mLooper,
                                callbacks);
            } else {
                if (mCallbacksDispatcher == null) {
                    throw new IllegalStateException("Accessibility window manager callback already "
                            + "cleared!");
                }
                mCallbacksDispatcher = null;
            }
        }

        public boolean hasWindowManagerEventDispatcher() {
            if (isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
                    | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
                logTrace(TAG + ".hasCallbacks",
                        FLAGS_MAGNIFICATION_CALLBACK | FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK);
            }
            return mCallbacksDispatcher != null;
        }

        public void onRectangleOnScreenRequested(int displayId, Rect rectangle) {
            if (isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
                logTrace(
                        TAG + ".onRectangleOnScreenRequested",
                        FLAGS_MAGNIFICATION_CALLBACK,
                        "rectangle={" + rectangle + "}");
            }
            if (mCallbacksDispatcher != null) {
                mCallbacksDispatcher.onRectangleOnScreenRequested(displayId, rectangle);
            }
        }

        private static final class UiChangesForAccessibilityCallbacksDispatcher {

            private static final String LOG_TAG = TAG_WITH_CLASS_NAME
                    ? "WindowManagerEventDispatcher" : TAG_WM;

            private static final boolean DEBUG_RECTANGLE_REQUESTED = false;

            private final AccessibilityControllerInternalImpl mAccessibilityTracing;

            @NonNull
            private final UiChangesForAccessibilityCallbacks mCallbacks;

            private final Handler mHandler;

            UiChangesForAccessibilityCallbacksDispatcher(
                    AccessibilityControllerInternalImpl accessibilityControllerInternal,
                    Looper looper, @NonNull UiChangesForAccessibilityCallbacks callbacks) {
                mAccessibilityTracing = accessibilityControllerInternal;
                mCallbacks = callbacks;
                mHandler = new Handler(looper);
            }

            void onRectangleOnScreenRequested(int displayId, Rect rectangle) {
                if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
                    mAccessibilityTracing.logTrace(LOG_TAG + ".onRectangleOnScreenRequested",
                            FLAGS_MAGNIFICATION_CALLBACK, "rectangle={" + rectangle + "}");
                }
                if (DEBUG_RECTANGLE_REQUESTED) {
                    Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
                }
                final Message m = PooledLambda.obtainMessage(
                        mCallbacks::onRectangleOnScreenRequested, displayId, rectangle.left,
                        rectangle.top, rectangle.right, rectangle.bottom);
                mHandler.sendMessage(m);
            }
        }
    }

    private static final class AccessibilityTracing {
+26 −0
Original line number Diff line number Diff line
@@ -104,6 +104,32 @@ public abstract class WindowManagerInternal {
        void logTrace(String where, long loggingTypeFlags, String callingParams,
                byte[] a11yDump, int callingUid, StackTraceElement[] callStack, long timeStamp,
                int processId, long threadId, Set<String> ignoreStackEntries);

        /**
         * Set by the accessibility related modules which want to listen the event dispatched from
         * window manager. Accessibility modules can use these callbacks to handle some display
         * manipulations.
         * @param callbacks The callbacks to invoke.
         */
        void setUiChangesForAccessibilityCallbacks(UiChangesForAccessibilityCallbacks callbacks);

        /**
         * This interface is used by window manager to dispatch some ui change events which may
         * affect the screen accessibility features.
         */
        interface UiChangesForAccessibilityCallbacks {
            /**
             * Called when an application requests a rectangle focus on the screen.
             *
             * @param displayId The logical display id
             * @param left The rectangle left.
             * @param top The rectangle top.
             * @param right The rectangle right.
             * @param bottom The rectangle bottom.
             */
            void onRectangleOnScreenRequested(int displayId, int left, int top, int right,
                    int bottom);
        }
    }

    /**
Loading