diff options
| author | 2024-04-18 12:53:49 +0000 | |
|---|---|---|
| committer | 2024-07-29 02:06:37 +0000 | |
| commit | 594afbcc4cf9fdc7c39d9ed07b8be121edc212e6 (patch) | |
| tree | eaa9f81efc7bd016c6addd281e743b954703b5f1 | |
| parent | a2cec2c5c4f84bdcd3d5321c5f59b6d7f9d1c9fa (diff) | |
fix(fullscreen border): Apply corner radius according to the display
Register DisplayListener and update the corner radius of the fullscreen
magnification border in onDisplayChanged.
Bug: 335113174
Test: atest FullscreenMagnificationControllerTest
Flag: com.android.systemui.update_corner_radius_on_display_changed
Change-Id: I317c6181629d8f9593f11a8ae835933183fb2ab0
3 files changed, 191 insertions, 5 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java index 3c0ac9a172f9..394f8dd629ae 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationImpl.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationImpl.java index e9c9bc7799a5..93c4630cd0cd 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationImpl.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationImpl.java @@ -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, diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java index cbd535ba7c2b..530ae158cf43 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java @@ -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); |