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

Commit c7b3ae47 authored by chihtinglo's avatar chihtinglo Committed by Candice
Browse files

fix(fullscreen magnification): Add orange Border from SysUI

Create FullscreenMagnificationController for handling fullscreen magnification stuffs in SystemUI:
1. The border is set to a thicker width to guarantee that there is no free space between the orange border and the device edges
2. The border is always fullscreen and will be added/removed on fullscreen magnification activation change

Bug: 291891390
Test: adb shell device_config put accessibility com.android.window.flags.always_draw_magnification_fullscreen_border true
      atest SystemUITests:FullscreenMagnificationControllerTest
      atest IMagnificationConnectionTest
Flag: ACONFIG always_draw_magnification_fullscreen_border DEVELOPMENT
Change-Id: Ib380cf0679f2f980c3504af27cca15047fd55ac5
parent db7588db
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2024 The Android Open Source Project
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~      http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <corners android:radius="@*android:dimen/rounded_corner_radius" />
    <!-- Since the device corners are not perfectly rounded, we create the stroke with offset
         to fill up the space between border and device corner -->
    <stroke
        android:color="@color/magnification_border_color"
        android:width="@dimen/magnifier_border_width_fullscreen_with_offset"/>
</shape>
 No newline at end of file
+22 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2024 The Android Open Source Project
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~      http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->
<View xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/magnification_fullscreen_border"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusable="false"
    android:background="@drawable/accessibility_fullscreen_magnification_border_background"/>
 No newline at end of file
+2 −0
Original line number Diff line number Diff line
@@ -1266,6 +1266,8 @@
    <dimen name="magnifier_corner_radius">28dp</dimen>
    <dimen name="magnifier_edit_corner_radius">16dp</dimen>
    <dimen name="magnifier_edit_outer_corner_radius">18dp</dimen>
    <dimen name="magnifier_border_width_fullscreen_with_offset">12dp</dimen>
    <dimen name="magnifier_border_width_fullscreen">6dp</dimen>
    <dimen name="magnifier_border_width">8dp</dimen>
    <dimen name="magnifier_stroke_width">2dp</dimen>
    <dimen name="magnifier_edit_dash_gap">20dp</dimen>
+140 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.accessibility;

import static android.view.WindowManager.LayoutParams;

import android.annotation.UiContext;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
import android.view.AttachedSurfaceControl;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;

import androidx.annotation.UiThread;

import com.android.systemui.res.R;

import java.util.function.Supplier;

class FullscreenMagnificationController {

    private final Context mContext;
    private final AccessibilityManager mAccessibilityManager;
    private final WindowManager mWindowManager;
    private Supplier<SurfaceControlViewHost> mScvhSupplier;
    private SurfaceControlViewHost mSurfaceControlViewHost;
    private Rect mWindowBounds;
    private SurfaceControl.Transaction mTransaction;
    private View mFullscreenBorder = null;
    private int mBorderOffset;
    private final int mDisplayId;
    private static final Region sEmptyRegion = new Region();

    FullscreenMagnificationController(
            @UiContext Context context,
            AccessibilityManager accessibilityManager,
            WindowManager windowManager,
            Supplier<SurfaceControlViewHost> scvhSupplier) {
        mContext = context;
        mAccessibilityManager = accessibilityManager;
        mWindowManager = windowManager;
        mWindowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
        mTransaction = new SurfaceControl.Transaction();
        mScvhSupplier = scvhSupplier;
        mBorderOffset = mContext.getResources().getDimensionPixelSize(
                R.dimen.magnifier_border_width_fullscreen_with_offset)
                - mContext.getResources().getDimensionPixelSize(
                R.dimen.magnifier_border_width_fullscreen);
        mDisplayId = mContext.getDisplayId();
    }

    @UiThread
    void onFullscreenMagnificationActivationChanged(boolean activated) {
        if (activated) {
            createFullscreenMagnificationBorder();
        } else {
            removeFullscreenMagnificationBorder();
        }
    }

    @UiThread
    private void removeFullscreenMagnificationBorder() {
        if (mSurfaceControlViewHost != null) {
            mSurfaceControlViewHost.release();
            mSurfaceControlViewHost = null;
        }

        if (mFullscreenBorder != null) {
            mFullscreenBorder = null;
        }
    }

    /**
     * Since the device corners are not perfectly rounded, we would like to create a thick stroke,
     * and set negative offset to the border view to fill up the spaces between the border and the
     * device corners.
     */
    @UiThread
    private void createFullscreenMagnificationBorder() {
        mFullscreenBorder = LayoutInflater.from(mContext)
                .inflate(R.layout.fullscreen_magnification_border, null);
        mSurfaceControlViewHost = mScvhSupplier.get();
        mSurfaceControlViewHost.setView(mFullscreenBorder, getBorderLayoutParams());

        SurfaceControl surfaceControl = mSurfaceControlViewHost
                .getSurfacePackage().getSurfaceControl();

        mTransaction
                .setPosition(surfaceControl, -mBorderOffset, -mBorderOffset)
                .setLayer(surfaceControl, Integer.MAX_VALUE)
                .show(surfaceControl)
                .apply();

        mAccessibilityManager.attachAccessibilityOverlayToDisplay(mDisplayId, surfaceControl);

        applyTouchableRegion();
    }

    private LayoutParams getBorderLayoutParams() {
        LayoutParams params =  new LayoutParams(
                mWindowBounds.width() + 2 * mBorderOffset,
                mWindowBounds.height() + 2 * mBorderOffset,
                LayoutParams.TYPE_ACCESSIBILITY_OVERLAY,
                LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSPARENT);
        params.setTrustedOverlay();
        return params;
    }

    private void applyTouchableRegion() {
        // Sometimes this can get posted and run after deleteWindowMagnification() is called.
        if (mFullscreenBorder == null) return;

        AttachedSurfaceControl surfaceControl = mSurfaceControlViewHost.getRootSurfaceControl();

        // The touchable region of the mFullscreenBorder will be empty since we are going to allow
        // all touch events to go through this view.
        surfaceControl.setTouchableRegion(sEmptyRegion);
    }
}
+40 −1
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IMagnificationConnection;
@@ -134,6 +135,37 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks {
    @VisibleForTesting
    DisplayIdIndexSupplier<WindowMagnificationController> mWindowMagnificationControllerSupplier;

    private static class FullscreenMagnificationControllerSupplier extends
            DisplayIdIndexSupplier<FullscreenMagnificationController> {

        private final Context mContext;

        FullscreenMagnificationControllerSupplier(Context context, Handler handler,
                DisplayManager displayManager, SysUiState sysUiState,
                SecureSettings secureSettings) {
            super(displayManager);
            mContext = context;
        }

        @Override
        protected FullscreenMagnificationController createInstance(Display display) {
            final Context windowContext = mContext.createWindowContext(display,
                    TYPE_ACCESSIBILITY_OVERLAY, /* options */ null);
            Supplier<SurfaceControlViewHost> scvhSupplier = () -> new SurfaceControlViewHost(
                    mContext, mContext.getDisplay(), new InputTransferToken(), TAG);
            windowContext.setTheme(com.android.systemui.res.R.style.Theme_SystemUI);
            return new FullscreenMagnificationController(
                    windowContext,
                    windowContext.getSystemService(AccessibilityManager.class),
                    windowContext.getSystemService(WindowManager.class),
                    scvhSupplier);
        }
    }

    @VisibleForTesting
    DisplayIdIndexSupplier<FullscreenMagnificationController>
            mFullscreenMagnificationControllerSupplier;

    private static class SettingsSupplier extends
            DisplayIdIndexSupplier<MagnificationSettingsController> {

@@ -185,6 +217,8 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks {
        mWindowMagnificationControllerSupplier = new WindowMagnificationControllerSupplier(context,
                mHandler, mWindowMagnifierCallback,
                displayManager, sysUiState, secureSettings);
        mFullscreenMagnificationControllerSupplier = new FullscreenMagnificationControllerSupplier(
                context, mHandler, displayManager, sysUiState, secureSettings);
        mMagnificationSettingsSupplier = new SettingsSupplier(context,
                mMagnificationSettingsControllerCallback, displayManager, secureSettings);

@@ -273,8 +307,13 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks {
        }
    }

    @MainThread
    void onFullscreenMagnificationActivationChanged(int displayId, boolean activated) {
        // Do nothing
        final FullscreenMagnificationController fullscreenMagnificationController =
                mFullscreenMagnificationControllerSupplier.get(displayId);
        if (fullscreenMagnificationController != null) {
            fullscreenMagnificationController.onFullscreenMagnificationActivationChanged(activated);
        }
    }

    @MainThread
Loading