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

Commit f7de2512 authored by Candice Lo's avatar Candice Lo Committed by Android (Google) Code Review
Browse files

Merge changes from topic "fullscreenMagnification_cornerRadius" into main

* changes:
  fix(fullscreen border): Apply corner radius according to the display
  fix(fullscreen border): Add flag for updating corner radius on display changed
parents 6a496f11 594afbcc
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -89,6 +89,16 @@ flag {
    }
}

flag {
    name: "update_corner_radius_on_display_changed"
    namespace: "accessibility"
    description: "Updates the corner radius to the magnification fullscreen border when the display changes."
    bug: "335113174"
    metadata {
      purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "hearing_devices_dialog_related_tools"
    namespace: "accessibility"
+69 −5
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.GradientDrawable;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.util.Log;
import android.view.AttachedSurfaceControl;
@@ -49,6 +51,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.UiThread;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.systemui.Flags;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.res.R;
import com.android.systemui.util.leak.RotationUtils;
@@ -70,6 +74,7 @@ public class FullscreenMagnificationController implements ComponentCallbacks {
    private SurfaceControl.Transaction mTransaction;
    private View mFullscreenBorder = null;
    private int mBorderOffset;
    private int mBorderStoke;
    private final int mDisplayId;
    private static final Region sEmptyRegion = new Region();
    private ValueAnimator mShowHideBorderAnimator;
@@ -86,16 +91,20 @@ public class FullscreenMagnificationController implements ComponentCallbacks {
        }
    };
    private final long mLongAnimationTimeMs;
    private final DisplayManager mDisplayManager;
    private final DisplayManager.DisplayListener mDisplayListener;
    private String mCurrentDisplayUniqueId;

    public FullscreenMagnificationController(
            @UiContext Context context,
            @Main Handler handler,
            @Main Executor executor,
            DisplayManager displayManager,
            AccessibilityManager accessibilityManager,
            WindowManager windowManager,
            IWindowManager iWindowManager,
            Supplier<SurfaceControlViewHost> scvhSupplier) {
        this(context, handler, executor, accessibilityManager,
        this(context, handler, executor, displayManager, accessibilityManager,
                windowManager, iWindowManager, scvhSupplier,
                new SurfaceControl.Transaction(), null);
    }
@@ -105,6 +114,7 @@ public class FullscreenMagnificationController implements ComponentCallbacks {
            @UiContext Context context,
            @Main Handler handler,
            @Main Executor executor,
            DisplayManager displayManager,
            AccessibilityManager accessibilityManager,
            WindowManager windowManager,
            IWindowManager iWindowManager,
@@ -120,10 +130,7 @@ public class FullscreenMagnificationController implements ComponentCallbacks {
        mWindowBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
        mTransaction = transaction;
        mScvhSupplier = scvhSupplier;
        mBorderOffset = mContext.getResources().getDimensionPixelSize(
                R.dimen.magnifier_border_width_fullscreen_with_offset)
                - mContext.getResources().getDimensionPixelSize(
                R.dimen.magnifier_border_width_fullscreen);
        updateDimensions();
        mDisplayId = mContext.getDisplayId();
        mConfiguration = new Configuration(context.getResources().getConfiguration());
        mLongAnimationTimeMs = mContext.getResources().getInteger(
@@ -140,6 +147,31 @@ public class FullscreenMagnificationController implements ComponentCallbacks {
                }
            }
        });
        mCurrentDisplayUniqueId = mContext.getDisplayNoVerify().getUniqueId();
        mDisplayManager = displayManager;
        mDisplayListener = new DisplayManager.DisplayListener() {
            @Override
            public void onDisplayAdded(int displayId) {
                // Do nothing
            }

            @Override
            public void onDisplayRemoved(int displayId) {
                // Do nothing
            }

            @Override
            public void onDisplayChanged(int displayId) {
                final String uniqueId = mContext.getDisplayNoVerify().getUniqueId();
                if (uniqueId.equals(mCurrentDisplayUniqueId)) {
                    // Same unique ID means the physical display doesn't change. Early return.
                    return;
                }

                mCurrentDisplayUniqueId = uniqueId;
                applyCornerRadiusToBorder();
            }
        };
    }

    private ValueAnimator createNullTargetObjectAnimator() {
@@ -180,10 +212,15 @@ public class FullscreenMagnificationController implements ComponentCallbacks {
        }
        mContext.unregisterComponentCallbacks(this);


        mShowHideBorderAnimator.reverse();
    }

    private void cleanUpBorder() {
        if (Flags.updateCornerRadiusOnDisplayChanged()) {
            mDisplayManager.unregisterDisplayListener(mDisplayListener);
        }

        if (mSurfaceControlViewHost != null) {
            mSurfaceControlViewHost.release();
            mSurfaceControlViewHost = null;
@@ -226,6 +263,9 @@ public class FullscreenMagnificationController implements ComponentCallbacks {
            } catch (Exception e) {
                Log.w(TAG, "Failed to register rotation watcher", e);
            }
            if (Flags.updateCornerRadiusOnDisplayChanged()) {
                mHandler.post(this::applyCornerRadiusToBorder);
            }
        }

        mTransaction
@@ -247,6 +287,9 @@ public class FullscreenMagnificationController implements ComponentCallbacks {

        mAccessibilityManager.attachAccessibilityOverlayToDisplay(
                mDisplayId, mBorderSurfaceControl);
        if (Flags.updateCornerRadiusOnDisplayChanged()) {
            mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
        }

        applyTouchableRegion();
    }
@@ -304,6 +347,11 @@ public class FullscreenMagnificationController implements ComponentCallbacks {
            final int newWidth = mWindowBounds.width() + 2 * mBorderOffset;
            final int newHeight = mWindowBounds.height() + 2 * mBorderOffset;
            mSurfaceControlViewHost.relayout(newWidth, newHeight);
            if (Flags.updateCornerRadiusOnDisplayChanged()) {
                // Recenter the border
                mTransaction.setPosition(
                        mBorderSurfaceControl, -mBorderOffset, -mBorderOffset).apply();
            }
        }

        // Rotating from Landscape to ReverseLandscape will not trigger the config changes in
@@ -352,6 +400,22 @@ public class FullscreenMagnificationController implements ComponentCallbacks {
                R.dimen.magnifier_border_width_fullscreen_with_offset)
                - mContext.getResources().getDimensionPixelSize(
                        R.dimen.magnifier_border_width_fullscreen);
        mBorderStoke = mContext.getResources().getDimensionPixelSize(
                R.dimen.magnifier_border_width_fullscreen_with_offset);
    }

    private void applyCornerRadiusToBorder() {
        if (!isActivated()) {
            return;
        }

        float cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext);
        GradientDrawable backgroundDrawable = (GradientDrawable) mFullscreenBorder.getBackground();
        backgroundDrawable.setStroke(
                mBorderStoke,
                mContext.getResources().getColor(
                        R.color.magnification_border_color, mContext.getTheme()));
        backgroundDrawable.setCornerRadius(cornerRadius);
    }

    @Override
+3 −0
Original line number Diff line number Diff line
@@ -149,6 +149,7 @@ public class MagnificationImpl implements Magnification, CommandQueue.Callbacks
        private final Context mContext;
        private final Handler mHandler;
        private final Executor mExecutor;
        private final DisplayManager mDisplayManager;
        private final IWindowManager mIWindowManager;

        FullscreenMagnificationControllerSupplier(Context context,
@@ -159,6 +160,7 @@ public class MagnificationImpl implements Magnification, CommandQueue.Callbacks
            mContext = context;
            mHandler = handler;
            mExecutor = executor;
            mDisplayManager = displayManager;
            mIWindowManager = iWindowManager;
        }

@@ -173,6 +175,7 @@ public class MagnificationImpl implements Magnification, CommandQueue.Callbacks
                    windowContext,
                    mHandler,
                    mExecutor,
                    mDisplayManager,
                    windowContext.getSystemService(AccessibilityManager.class),
                    windowContext.getSystemService(WindowManager.class),
                    mIWindowManager,
+119 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertWithMessage;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -36,7 +37,10 @@ import android.animation.ValueAnimator;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.hardware.display.DisplayManager;
import android.os.RemoteException;
import android.platform.test.annotations.EnableFlags;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Display;
@@ -54,6 +58,7 @@ import android.window.InputTransferToken;
import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;

import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.res.R;

@@ -61,6 +66,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@@ -76,6 +82,12 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase {
    private static final long WAIT_TIMEOUT_S = 5L * HW_TIMEOUT_MULTIPLIER;
    private static final long ANIMATION_TIMEOUT_MS =
            5L * ANIMATION_DURATION_MS * HW_TIMEOUT_MULTIPLIER;

    private static final String UNIQUE_DISPLAY_ID_PRIMARY = "000";
    private static final String UNIQUE_DISPLAY_ID_SECONDARY = "111";
    private static final int CORNER_RADIUS_PRIMARY = 10;
    private static final int CORNER_RADIUS_SECONDARY = 20;

    private FullscreenMagnificationController mFullscreenMagnificationController;
    private SurfaceControlViewHost mSurfaceControlViewHost;
    private ValueAnimator mShowHideBorderAnimator;
@@ -83,10 +95,35 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase {
    private TestableWindowManager mWindowManager;
    @Mock
    private IWindowManager mIWindowManager;
    @Mock
    private DisplayManager mDisplayManager;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mContext = spy(mContext);
        Display display = mock(Display.class);
        when(display.getUniqueId()).thenReturn(UNIQUE_DISPLAY_ID_PRIMARY);
        when(mContext.getDisplayNoVerify()).thenReturn(display);

        // Override the resources to Display Primary
        mContext.getOrCreateTestableResources()
                .addOverride(
                        com.android.internal.R.dimen.rounded_corner_radius,
                        CORNER_RADIUS_PRIMARY);
        mContext.getOrCreateTestableResources()
                .addOverride(com.android.internal.R.dimen.rounded_corner_radius_adjustment, 0);
        mContext.getOrCreateTestableResources()
                .addOverride(com.android.internal.R.dimen.rounded_corner_radius_top, 0);
        mContext.getOrCreateTestableResources()
                .addOverride(
                        com.android.internal.R.dimen.rounded_corner_radius_top_adjustment, 0);
        mContext.getOrCreateTestableResources()
                .addOverride(com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
        mContext.getOrCreateTestableResources()
                .addOverride(
                        com.android.internal.R.dimen.rounded_corner_radius_bottom_adjustment, 0);

        getInstrumentation().runOnMainSync(() -> mSurfaceControlViewHost =
                spy(new SurfaceControlViewHost(mContext, mContext.getDisplay(),
                        new InputTransferToken(), "FullscreenMagnification")));
@@ -101,6 +138,7 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase {
                mContext,
                mContext.getMainThreadHandler(),
                mContext.getMainExecutor(),
                mDisplayManager,
                mContext.getSystemService(AccessibilityManager.class),
                mContext.getSystemService(WindowManager.class),
                mIWindowManager,
@@ -259,6 +297,87 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase {
        verify(mSurfaceControlViewHost).relayout(newWidth, newHeight);
    }

    @EnableFlags(Flags.FLAG_UPDATE_CORNER_RADIUS_ON_DISPLAY_CHANGED)
    @Test
    public void enableFullscreenMagnification_applyPrimaryCornerRadius()
            throws InterruptedException {
        CountDownLatch transactionCommittedLatch = new CountDownLatch(1);
        CountDownLatch animationEndLatch = new CountDownLatch(1);
        mTransaction.addTransactionCommittedListener(
                Runnable::run, transactionCommittedLatch::countDown);
        mShowHideBorderAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                animationEndLatch.countDown();
            }
        });

        getInstrumentation().runOnMainSync(() ->
                //Enable fullscreen magnification
                mFullscreenMagnificationController
                        .onFullscreenMagnificationActivationChanged(true));
        assertWithMessage("Failed to wait for transaction committed")
                .that(transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS))
                .isTrue();
        assertWithMessage("Failed to wait for animation to be finished")
                .that(animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS))
                .isTrue();

        // Verify the initial corner radius is applied
        GradientDrawable backgroundDrawable =
                (GradientDrawable) mSurfaceControlViewHost.getView().getBackground();
        assertThat(backgroundDrawable.getCornerRadius()).isEqualTo(CORNER_RADIUS_PRIMARY);
    }

    @EnableFlags(Flags.FLAG_UPDATE_CORNER_RADIUS_ON_DISPLAY_CHANGED)
    @Test
    public void onDisplayChanged_updateCornerRadiusToSecondary() throws InterruptedException {
        CountDownLatch transactionCommittedLatch = new CountDownLatch(1);
        CountDownLatch animationEndLatch = new CountDownLatch(1);
        mTransaction.addTransactionCommittedListener(
                Runnable::run, transactionCommittedLatch::countDown);
        mShowHideBorderAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                animationEndLatch.countDown();
            }
        });

        getInstrumentation().runOnMainSync(() ->
                //Enable fullscreen magnification
                mFullscreenMagnificationController
                        .onFullscreenMagnificationActivationChanged(true));
        assertWithMessage("Failed to wait for transaction committed")
                .that(transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS))
                .isTrue();
        assertWithMessage("Failed to wait for animation to be finished")
                .that(animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS))
                .isTrue();

        ArgumentCaptor<DisplayManager.DisplayListener> displayListenerCaptor =
                ArgumentCaptor.forClass(DisplayManager.DisplayListener.class);
        verify(mDisplayManager).registerDisplayListener(displayListenerCaptor.capture(), any());

        Display newDisplay = mock(Display.class);
        when(newDisplay.getUniqueId()).thenReturn(UNIQUE_DISPLAY_ID_SECONDARY);
        when(mContext.getDisplayNoVerify()).thenReturn(newDisplay);
        // Override the resources to Display Secondary
        mContext.getOrCreateTestableResources()
                .removeOverride(com.android.internal.R.dimen.rounded_corner_radius);
        mContext.getOrCreateTestableResources()
                .addOverride(
                        com.android.internal.R.dimen.rounded_corner_radius,
                        CORNER_RADIUS_SECONDARY);
        getInstrumentation().runOnMainSync(() ->
                displayListenerCaptor.getValue().onDisplayChanged(Display.DEFAULT_DISPLAY));
        waitForIdleSync();
        // Verify the corner radius is updated
        GradientDrawable backgroundDrawable2 =
                (GradientDrawable) mSurfaceControlViewHost.getView().getBackground();
        assertThat(backgroundDrawable2.getCornerRadius()).isEqualTo(CORNER_RADIUS_SECONDARY);
    }


    private ValueAnimator newNullTargetObjectAnimator() {
        final ValueAnimator animator =
                ObjectAnimator.ofFloat(/* target= */ null, View.ALPHA, 0f, 1f);