Loading packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java +93 −9 Original line number Diff line number Diff line Loading @@ -30,7 +30,12 @@ import android.content.res.Configuration; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; import android.os.Handler; import android.util.Log; import android.view.AttachedSurfaceControl; import android.view.Display; import android.view.IRotationWatcher; import android.view.IWindowManager; import android.view.LayoutInflater; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; Loading @@ -46,15 +51,18 @@ import androidx.annotation.UiThread; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.res.R; import com.android.systemui.util.leak.RotationUtils; import java.util.concurrent.Executor; import java.util.function.Supplier; class FullscreenMagnificationController implements ComponentCallbacks { private static final String TAG = "FullscreenMagnificationController"; private final Context mContext; private final AccessibilityManager mAccessibilityManager; private final WindowManager mWindowManager; private final IWindowManager mIWindowManager; private Supplier<SurfaceControlViewHost> mScvhSupplier; private SurfaceControlViewHost mSurfaceControlViewHost = null; private SurfaceControl mBorderSurfaceControl = null; Loading @@ -65,33 +73,50 @@ class FullscreenMagnificationController implements ComponentCallbacks { private final int mDisplayId; private static final Region sEmptyRegion = new Region(); private ValueAnimator mShowHideBorderAnimator; private Handler mHandler; private Executor mExecutor; private boolean mFullscreenMagnificationActivated = false; private final Configuration mConfiguration; private final Runnable mShowBorderRunnable = this::showBorderWithNullCheck; private int mRotation; private final IRotationWatcher mRotationWatcher = new IRotationWatcher.Stub() { @Override public void onRotationChanged(final int rotation) { handleScreenRotation(); } }; private final long mLongAnimationTimeMs; FullscreenMagnificationController( @UiContext Context context, Executor executor, @Main Handler handler, @Main Executor executor, AccessibilityManager accessibilityManager, WindowManager windowManager, IWindowManager iWindowManager, Supplier<SurfaceControlViewHost> scvhSupplier) { this(context, executor, accessibilityManager, windowManager, scvhSupplier, new SurfaceControl.Transaction(), createNullTargetObjectAnimator(context)); this(context, handler, executor, accessibilityManager, windowManager, iWindowManager, scvhSupplier, new SurfaceControl.Transaction(), null); } @VisibleForTesting FullscreenMagnificationController( @UiContext Context context, @Main Handler handler, @Main Executor executor, AccessibilityManager accessibilityManager, WindowManager windowManager, IWindowManager iWindowManager, Supplier<SurfaceControlViewHost> scvhSupplier, SurfaceControl.Transaction transaction, ValueAnimator valueAnimator) { mContext = context; mHandler = handler; mExecutor = executor; mAccessibilityManager = accessibilityManager; mWindowManager = windowManager; mIWindowManager = iWindowManager; mWindowBounds = mWindowManager.getCurrentWindowMetrics().getBounds(); mTransaction = transaction; mScvhSupplier = scvhSupplier; Loading @@ -101,7 +126,10 @@ class FullscreenMagnificationController implements ComponentCallbacks { R.dimen.magnifier_border_width_fullscreen); mDisplayId = mContext.getDisplayId(); mConfiguration = new Configuration(context.getResources().getConfiguration()); mShowHideBorderAnimator = valueAnimator; mLongAnimationTimeMs = mContext.getResources().getInteger( com.android.internal.R.integer.config_longAnimTime); mShowHideBorderAnimator = (valueAnimator == null) ? createNullTargetObjectAnimator() : valueAnimator; mShowHideBorderAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) { Loading @@ -114,15 +142,13 @@ class FullscreenMagnificationController implements ComponentCallbacks { }); } private static ValueAnimator createNullTargetObjectAnimator(Context context) { private ValueAnimator createNullTargetObjectAnimator() { final ValueAnimator valueAnimator = ObjectAnimator.ofFloat(/* target= */ null, View.ALPHA, 0f, 1f); Interpolator interpolator = new AccelerateDecelerateInterpolator(); final long longAnimationDuration = context.getResources().getInteger( com.android.internal.R.integer.config_longAnimTime); valueAnimator.setInterpolator(interpolator); valueAnimator.setDuration(longAnimationDuration); valueAnimator.setDuration(mLongAnimationTimeMs); return valueAnimator; } Loading @@ -149,7 +175,11 @@ class FullscreenMagnificationController implements ComponentCallbacks { */ @UiThread private void removeFullscreenMagnificationBorder() { if (mHandler.hasCallbacks(mShowBorderRunnable)) { mHandler.removeCallbacks(mShowBorderRunnable); } mContext.unregisterComponentCallbacks(this); mShowHideBorderAnimator.reverse(); } Loading @@ -161,6 +191,11 @@ class FullscreenMagnificationController implements ComponentCallbacks { if (mFullscreenBorder != null) { mFullscreenBorder = null; try { mIWindowManager.removeRotationWatcher(mRotationWatcher); } catch (Exception e) { Log.w(TAG, "Failed to remove rotation watcher", e); } } } Loading @@ -186,6 +221,11 @@ class FullscreenMagnificationController implements ComponentCallbacks { mSurfaceControlViewHost = mScvhSupplier.get(); mSurfaceControlViewHost.setView(mFullscreenBorder, getBorderLayoutParams()); mBorderSurfaceControl = mSurfaceControlViewHost.getSurfacePackage().getSurfaceControl(); try { mIWindowManager.watchRotation(mRotationWatcher, Display.DEFAULT_DISPLAY); } catch (Exception e) { Log.w(TAG, "Failed to register rotation watcher", e); } } mTransaction Loading Loading @@ -256,11 +296,55 @@ class FullscreenMagnificationController implements ComponentCallbacks { reCreateWindow = true; } if (mFullscreenBorder != null && reCreateWindow) { if (mFullscreenBorder == null) { return; } if (reCreateWindow) { final int newWidth = mWindowBounds.width() + 2 * mBorderOffset; final int newHeight = mWindowBounds.height() + 2 * mBorderOffset; mSurfaceControlViewHost.relayout(newWidth, newHeight); } // Rotating from Landscape to ReverseLandscape will not trigger the config changes in // CONFIG_SCREEN_SIZE and CONFIG_ORIENTATION. Therefore, we would like to check the device // rotation separately. // Since there's a possibility that {@link onConfigurationChanged} comes before // {@link onRotationChanged}, we would like to handle screen rotation in either case that // happens earlier. int newRotation = RotationUtils.getRotation(mContext); if (newRotation != mRotation) { mRotation = newRotation; handleScreenRotation(); } } private boolean isActivated() { return mFullscreenBorder != null; } private void handleScreenRotation() { if (!isActivated()) { return; } if (mHandler.hasCallbacks(mShowBorderRunnable)) { mHandler.removeCallbacks(mShowBorderRunnable); } // We hide the border immediately as early as possible to beat the redrawing of window // in response to the orientation change so users won't see a weird shape border. mHandler.postAtFrontOfQueue(() -> { mFullscreenBorder.setAlpha(0f); }); mHandler.postDelayed(mShowBorderRunnable, mLongAnimationTimeMs); } private void showBorderWithNullCheck() { if (mShowHideBorderAnimator != null) { mShowHideBorderAnimator.start(); } } private void updateDimensions() { Loading packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java +19 −7 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.os.Looper; import android.os.Message; import android.util.SparseArray; import android.view.Display; import android.view.IWindowManager; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; import android.view.WindowManager; Loading Loading @@ -148,13 +149,19 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks { DisplayIdIndexSupplier<FullscreenMagnificationController> { private final Context mContext; private final Handler mHandler; private final Executor mExecutor; private final IWindowManager mIWindowManager; FullscreenMagnificationControllerSupplier(Context context, DisplayManager displayManager, Executor executor) { FullscreenMagnificationControllerSupplier(Context context, DisplayManager displayManager, Handler handler, Executor executor, IWindowManager iWindowManager) { super(displayManager); mContext = context; mHandler = handler; mExecutor = executor; mIWindowManager = iWindowManager; } @Override Loading @@ -166,9 +173,11 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks { windowContext.setTheme(com.android.systemui.res.R.style.Theme_SystemUI); return new FullscreenMagnificationController( windowContext, mHandler, mExecutor, windowContext.getSystemService(AccessibilityManager.class), windowContext.getSystemService(WindowManager.class), mIWindowManager, scvhSupplier); } } Loading Loading @@ -211,14 +220,16 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks { DisplayIdIndexSupplier<MagnificationSettingsController> mMagnificationSettingsSupplier; @Inject public Magnification(Context context, @Main Handler mainHandler, @Main Executor executor, public Magnification(Context context, @Main Handler mainHandler, @Main Executor executor, CommandQueue commandQueue, ModeSwitchesController modeSwitchesController, SysUiState sysUiState, OverviewProxyService overviewProxyService, SecureSettings secureSettings, DisplayTracker displayTracker, DisplayManager displayManager, AccessibilityLogger a11yLogger) { DisplayManager displayManager, AccessibilityLogger a11yLogger, IWindowManager iWindowManager) { this(context, mainHandler.getLooper(), executor, commandQueue, modeSwitchesController, sysUiState, overviewProxyService, secureSettings, displayTracker, displayManager, a11yLogger); displayTracker, displayManager, a11yLogger, iWindowManager); } @VisibleForTesting Loading @@ -226,7 +237,8 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks { CommandQueue commandQueue, ModeSwitchesController modeSwitchesController, SysUiState sysUiState, OverviewProxyService overviewProxyService, SecureSettings secureSettings, DisplayTracker displayTracker, DisplayManager displayManager, AccessibilityLogger a11yLogger) { DisplayManager displayManager, AccessibilityLogger a11yLogger, IWindowManager iWindowManager) { mContext = context; mHandler = new Handler(looper) { @Override Loading @@ -248,7 +260,7 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks { mHandler, mWindowMagnifierCallback, displayManager, sysUiState, secureSettings); mFullscreenMagnificationControllerSupplier = new FullscreenMagnificationControllerSupplier( context, displayManager, mExecutor); context, displayManager, mHandler, mExecutor, iWindowManager); mMagnificationSettingsSupplier = new SettingsSupplier(context, mMagnificationSettingsControllerCallback, displayManager, secureSettings); Loading packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java +47 −23 Original line number Diff line number Diff line Loading @@ -21,8 +21,10 @@ import static android.os.Build.HW_TIMEOUT_MULTIPLIER; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading @@ -34,8 +36,12 @@ import android.animation.ValueAnimator; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.os.RemoteException; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.Display; import android.view.IRotationWatcher; import android.view.IWindowManager; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; import android.view.View; Loading @@ -55,6 +61,8 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; Loading @@ -73,9 +81,12 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { private ValueAnimator mShowHideBorderAnimator; private SurfaceControl.Transaction mTransaction; private TestableWindowManager mWindowManager; @Mock private IWindowManager mIWindowManager; @Before public void setUp() { MockitoAnnotations.initMocks(this); getInstrumentation().runOnMainSync(() -> mSurfaceControlViewHost = spy(new SurfaceControlViewHost(mContext, mContext.getDisplay(), new InputTransferToken(), "FullscreenMagnification"))); Loading @@ -88,9 +99,11 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { mShowHideBorderAnimator = spy(newNullTargetObjectAnimator()); mFullscreenMagnificationController = new FullscreenMagnificationController( mContext, mContext.getMainThreadHandler(), mContext.getMainExecutor(), mContext.getSystemService(AccessibilityManager.class), mContext.getSystemService(WindowManager.class), mIWindowManager, scvhSupplier, mTransaction, mShowHideBorderAnimator); Loading @@ -104,7 +117,8 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { } @Test public void enableFullscreenMagnification_visibleBorder() throws InterruptedException { public void enableFullscreenMagnification_visibleBorder() throws InterruptedException, RemoteException { CountDownLatch transactionCommittedLatch = new CountDownLatch(1); CountDownLatch animationEndLatch = new CountDownLatch(1); mTransaction.addTransactionCommittedListener( Loading @@ -119,17 +133,21 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { //Enable fullscreen magnification mFullscreenMagnificationController .onFullscreenMagnificationActivationChanged(true)); assertTrue("Failed to wait for transaction committed", transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS)); assertTrue("Failed to wait for animation to be finished", animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)); 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(mShowHideBorderAnimator).start(); verify(mIWindowManager) .watchRotation(any(IRotationWatcher.class), eq(Display.DEFAULT_DISPLAY)); assertThat(mSurfaceControlViewHost.getView().isVisibleToUser()).isTrue(); } @Test public void disableFullscreenMagnification_reverseAnimationAndReleaseScvh() throws InterruptedException { throws InterruptedException, RemoteException { CountDownLatch transactionCommittedLatch = new CountDownLatch(1); CountDownLatch enableAnimationEndLatch = new CountDownLatch(1); CountDownLatch disableAnimationEndLatch = new CountDownLatch(1); Loading @@ -149,11 +167,12 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { //Enable fullscreen magnification mFullscreenMagnificationController .onFullscreenMagnificationActivationChanged(true)); assertTrue("Failed to wait for transaction committed", transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS)); assertTrue("Failed to wait for enabling animation to be finished", enableAnimationEndLatch.await( ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertWithMessage("Failed to wait for transaction committed") .that(transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS)) .isTrue(); assertWithMessage("Failed to wait for enabling animation to be finished") .that(enableAnimationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)) .isTrue(); verify(mShowHideBorderAnimator).start(); getInstrumentation().runOnMainSync(() -> Loading @@ -161,11 +180,12 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { mFullscreenMagnificationController .onFullscreenMagnificationActivationChanged(false)); assertTrue("Failed to wait for disabling animation to be finished", disableAnimationEndLatch.await( ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertWithMessage("Failed to wait for disabling animation to be finished") .that(disableAnimationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)) .isTrue(); verify(mShowHideBorderAnimator).reverse(); verify(mSurfaceControlViewHost).release(); verify(mIWindowManager).removeRotationWatcher(any(IRotationWatcher.class)); } @Test Loading @@ -188,10 +208,12 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { () -> mFullscreenMagnificationController .onFullscreenMagnificationActivationChanged(true)); assertTrue("Failed to wait for transaction committed", transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS)); assertTrue("Failed to wait for animation to be finished", animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)); 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(mShowHideBorderAnimator).reverse(); } Loading @@ -212,10 +234,12 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { //Enable fullscreen magnification mFullscreenMagnificationController .onFullscreenMagnificationActivationChanged(true)); assertTrue("Failed to wait for transaction committed", transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS)); assertTrue("Failed to wait for animation to be finished", animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)); 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(); final Rect testWindowBounds = new Rect( mWindowManager.getCurrentWindowMetrics().getBounds()); testWindowBounds.set(testWindowBounds.left, testWindowBounds.top, Loading packages/SystemUI/tests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java +6 −2 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import android.testing.TestableLooper; import android.view.Display; import android.view.IWindowManager; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IMagnificationConnection; import android.view.accessibility.IMagnificationConnectionCallback; Loading Loading @@ -99,6 +100,8 @@ public class IMagnificationConnectionTest extends SysuiTestCase { private SecureSettings mSecureSettings; @Mock private AccessibilityLogger mA11yLogger; @Mock private IWindowManager mIWindowManager; private IMagnificationConnection mIMagnificationConnection; private Magnification mMagnification; Loading @@ -117,9 +120,10 @@ public class IMagnificationConnectionTest extends SysuiTestCase { mTestableLooper = TestableLooper.get(this); assertNotNull(mTestableLooper); mMagnification = new Magnification(getContext(), mTestableLooper.getLooper(), getContext().getMainExecutor(), mCommandQueue, mTestableLooper.getLooper(), mContext.getMainExecutor(), mCommandQueue, mModeSwitchesController, mSysUiState, mOverviewProxyService, mSecureSettings, mDisplayTracker, getContext().getSystemService(DisplayManager.class), mA11yLogger); mDisplayTracker, getContext().getSystemService(DisplayManager.class), mA11yLogger, mIWindowManager); mMagnification.mWindowMagnificationControllerSupplier = new FakeWindowMagnificationControllerSupplier( mContext.getSystemService(DisplayManager.class)); Loading packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java +5 −2 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import android.hardware.display.DisplayManager; import android.os.RemoteException; import android.testing.TestableLooper; import android.view.Display; import android.view.IWindowManager; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IMagnificationConnection; import android.view.accessibility.IMagnificationConnectionCallback; Loading Loading @@ -93,6 +94,8 @@ public class MagnificationTest extends SysuiTestCase { private MagnificationSettingsController mMagnificationSettingsController; @Mock private AccessibilityLogger mA11yLogger; @Mock private IWindowManager mIWindowManager; @Before public void setUp() throws Exception { Loading Loading @@ -122,10 +125,10 @@ public class MagnificationTest extends SysuiTestCase { mCommandQueue = new CommandQueue(getContext(), mDisplayTracker); mMagnification = new Magnification(getContext(), getContext().getMainThreadHandler(), getContext().getMainExecutor(), getContext().getMainThreadHandler(), mContext.getMainExecutor(), mCommandQueue, mModeSwitchesController, mSysUiState, mOverviewProxyService, mSecureSettings, mDisplayTracker, getContext().getSystemService(DisplayManager.class), mA11yLogger); getContext().getSystemService(DisplayManager.class), mA11yLogger, mIWindowManager); mMagnification.mWindowMagnificationControllerSupplier = new FakeControllerSupplier( mContext.getSystemService(DisplayManager.class), mWindowMagnificationController); mMagnification.mMagnificationSettingsSupplier = new FakeSettingsSupplier( Loading Loading
packages/SystemUI/src/com/android/systemui/accessibility/FullscreenMagnificationController.java +93 −9 Original line number Diff line number Diff line Loading @@ -30,7 +30,12 @@ import android.content.res.Configuration; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; import android.os.Handler; import android.util.Log; import android.view.AttachedSurfaceControl; import android.view.Display; import android.view.IRotationWatcher; import android.view.IWindowManager; import android.view.LayoutInflater; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; Loading @@ -46,15 +51,18 @@ import androidx.annotation.UiThread; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.res.R; import com.android.systemui.util.leak.RotationUtils; import java.util.concurrent.Executor; import java.util.function.Supplier; class FullscreenMagnificationController implements ComponentCallbacks { private static final String TAG = "FullscreenMagnificationController"; private final Context mContext; private final AccessibilityManager mAccessibilityManager; private final WindowManager mWindowManager; private final IWindowManager mIWindowManager; private Supplier<SurfaceControlViewHost> mScvhSupplier; private SurfaceControlViewHost mSurfaceControlViewHost = null; private SurfaceControl mBorderSurfaceControl = null; Loading @@ -65,33 +73,50 @@ class FullscreenMagnificationController implements ComponentCallbacks { private final int mDisplayId; private static final Region sEmptyRegion = new Region(); private ValueAnimator mShowHideBorderAnimator; private Handler mHandler; private Executor mExecutor; private boolean mFullscreenMagnificationActivated = false; private final Configuration mConfiguration; private final Runnable mShowBorderRunnable = this::showBorderWithNullCheck; private int mRotation; private final IRotationWatcher mRotationWatcher = new IRotationWatcher.Stub() { @Override public void onRotationChanged(final int rotation) { handleScreenRotation(); } }; private final long mLongAnimationTimeMs; FullscreenMagnificationController( @UiContext Context context, Executor executor, @Main Handler handler, @Main Executor executor, AccessibilityManager accessibilityManager, WindowManager windowManager, IWindowManager iWindowManager, Supplier<SurfaceControlViewHost> scvhSupplier) { this(context, executor, accessibilityManager, windowManager, scvhSupplier, new SurfaceControl.Transaction(), createNullTargetObjectAnimator(context)); this(context, handler, executor, accessibilityManager, windowManager, iWindowManager, scvhSupplier, new SurfaceControl.Transaction(), null); } @VisibleForTesting FullscreenMagnificationController( @UiContext Context context, @Main Handler handler, @Main Executor executor, AccessibilityManager accessibilityManager, WindowManager windowManager, IWindowManager iWindowManager, Supplier<SurfaceControlViewHost> scvhSupplier, SurfaceControl.Transaction transaction, ValueAnimator valueAnimator) { mContext = context; mHandler = handler; mExecutor = executor; mAccessibilityManager = accessibilityManager; mWindowManager = windowManager; mIWindowManager = iWindowManager; mWindowBounds = mWindowManager.getCurrentWindowMetrics().getBounds(); mTransaction = transaction; mScvhSupplier = scvhSupplier; Loading @@ -101,7 +126,10 @@ class FullscreenMagnificationController implements ComponentCallbacks { R.dimen.magnifier_border_width_fullscreen); mDisplayId = mContext.getDisplayId(); mConfiguration = new Configuration(context.getResources().getConfiguration()); mShowHideBorderAnimator = valueAnimator; mLongAnimationTimeMs = mContext.getResources().getInteger( com.android.internal.R.integer.config_longAnimTime); mShowHideBorderAnimator = (valueAnimator == null) ? createNullTargetObjectAnimator() : valueAnimator; mShowHideBorderAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) { Loading @@ -114,15 +142,13 @@ class FullscreenMagnificationController implements ComponentCallbacks { }); } private static ValueAnimator createNullTargetObjectAnimator(Context context) { private ValueAnimator createNullTargetObjectAnimator() { final ValueAnimator valueAnimator = ObjectAnimator.ofFloat(/* target= */ null, View.ALPHA, 0f, 1f); Interpolator interpolator = new AccelerateDecelerateInterpolator(); final long longAnimationDuration = context.getResources().getInteger( com.android.internal.R.integer.config_longAnimTime); valueAnimator.setInterpolator(interpolator); valueAnimator.setDuration(longAnimationDuration); valueAnimator.setDuration(mLongAnimationTimeMs); return valueAnimator; } Loading @@ -149,7 +175,11 @@ class FullscreenMagnificationController implements ComponentCallbacks { */ @UiThread private void removeFullscreenMagnificationBorder() { if (mHandler.hasCallbacks(mShowBorderRunnable)) { mHandler.removeCallbacks(mShowBorderRunnable); } mContext.unregisterComponentCallbacks(this); mShowHideBorderAnimator.reverse(); } Loading @@ -161,6 +191,11 @@ class FullscreenMagnificationController implements ComponentCallbacks { if (mFullscreenBorder != null) { mFullscreenBorder = null; try { mIWindowManager.removeRotationWatcher(mRotationWatcher); } catch (Exception e) { Log.w(TAG, "Failed to remove rotation watcher", e); } } } Loading @@ -186,6 +221,11 @@ class FullscreenMagnificationController implements ComponentCallbacks { mSurfaceControlViewHost = mScvhSupplier.get(); mSurfaceControlViewHost.setView(mFullscreenBorder, getBorderLayoutParams()); mBorderSurfaceControl = mSurfaceControlViewHost.getSurfacePackage().getSurfaceControl(); try { mIWindowManager.watchRotation(mRotationWatcher, Display.DEFAULT_DISPLAY); } catch (Exception e) { Log.w(TAG, "Failed to register rotation watcher", e); } } mTransaction Loading Loading @@ -256,11 +296,55 @@ class FullscreenMagnificationController implements ComponentCallbacks { reCreateWindow = true; } if (mFullscreenBorder != null && reCreateWindow) { if (mFullscreenBorder == null) { return; } if (reCreateWindow) { final int newWidth = mWindowBounds.width() + 2 * mBorderOffset; final int newHeight = mWindowBounds.height() + 2 * mBorderOffset; mSurfaceControlViewHost.relayout(newWidth, newHeight); } // Rotating from Landscape to ReverseLandscape will not trigger the config changes in // CONFIG_SCREEN_SIZE and CONFIG_ORIENTATION. Therefore, we would like to check the device // rotation separately. // Since there's a possibility that {@link onConfigurationChanged} comes before // {@link onRotationChanged}, we would like to handle screen rotation in either case that // happens earlier. int newRotation = RotationUtils.getRotation(mContext); if (newRotation != mRotation) { mRotation = newRotation; handleScreenRotation(); } } private boolean isActivated() { return mFullscreenBorder != null; } private void handleScreenRotation() { if (!isActivated()) { return; } if (mHandler.hasCallbacks(mShowBorderRunnable)) { mHandler.removeCallbacks(mShowBorderRunnable); } // We hide the border immediately as early as possible to beat the redrawing of window // in response to the orientation change so users won't see a weird shape border. mHandler.postAtFrontOfQueue(() -> { mFullscreenBorder.setAlpha(0f); }); mHandler.postDelayed(mShowBorderRunnable, mLongAnimationTimeMs); } private void showBorderWithNullCheck() { if (mShowHideBorderAnimator != null) { mShowHideBorderAnimator.start(); } } private void updateDimensions() { Loading
packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java +19 −7 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.os.Looper; import android.os.Message; import android.util.SparseArray; import android.view.Display; import android.view.IWindowManager; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; import android.view.WindowManager; Loading Loading @@ -148,13 +149,19 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks { DisplayIdIndexSupplier<FullscreenMagnificationController> { private final Context mContext; private final Handler mHandler; private final Executor mExecutor; private final IWindowManager mIWindowManager; FullscreenMagnificationControllerSupplier(Context context, DisplayManager displayManager, Executor executor) { FullscreenMagnificationControllerSupplier(Context context, DisplayManager displayManager, Handler handler, Executor executor, IWindowManager iWindowManager) { super(displayManager); mContext = context; mHandler = handler; mExecutor = executor; mIWindowManager = iWindowManager; } @Override Loading @@ -166,9 +173,11 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks { windowContext.setTheme(com.android.systemui.res.R.style.Theme_SystemUI); return new FullscreenMagnificationController( windowContext, mHandler, mExecutor, windowContext.getSystemService(AccessibilityManager.class), windowContext.getSystemService(WindowManager.class), mIWindowManager, scvhSupplier); } } Loading Loading @@ -211,14 +220,16 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks { DisplayIdIndexSupplier<MagnificationSettingsController> mMagnificationSettingsSupplier; @Inject public Magnification(Context context, @Main Handler mainHandler, @Main Executor executor, public Magnification(Context context, @Main Handler mainHandler, @Main Executor executor, CommandQueue commandQueue, ModeSwitchesController modeSwitchesController, SysUiState sysUiState, OverviewProxyService overviewProxyService, SecureSettings secureSettings, DisplayTracker displayTracker, DisplayManager displayManager, AccessibilityLogger a11yLogger) { DisplayManager displayManager, AccessibilityLogger a11yLogger, IWindowManager iWindowManager) { this(context, mainHandler.getLooper(), executor, commandQueue, modeSwitchesController, sysUiState, overviewProxyService, secureSettings, displayTracker, displayManager, a11yLogger); displayTracker, displayManager, a11yLogger, iWindowManager); } @VisibleForTesting Loading @@ -226,7 +237,8 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks { CommandQueue commandQueue, ModeSwitchesController modeSwitchesController, SysUiState sysUiState, OverviewProxyService overviewProxyService, SecureSettings secureSettings, DisplayTracker displayTracker, DisplayManager displayManager, AccessibilityLogger a11yLogger) { DisplayManager displayManager, AccessibilityLogger a11yLogger, IWindowManager iWindowManager) { mContext = context; mHandler = new Handler(looper) { @Override Loading @@ -248,7 +260,7 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks { mHandler, mWindowMagnifierCallback, displayManager, sysUiState, secureSettings); mFullscreenMagnificationControllerSupplier = new FullscreenMagnificationControllerSupplier( context, displayManager, mExecutor); context, displayManager, mHandler, mExecutor, iWindowManager); mMagnificationSettingsSupplier = new SettingsSupplier(context, mMagnificationSettingsControllerCallback, displayManager, secureSettings); Loading
packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java +47 −23 Original line number Diff line number Diff line Loading @@ -21,8 +21,10 @@ import static android.os.Build.HW_TIMEOUT_MULTIPLIER; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading @@ -34,8 +36,12 @@ import android.animation.ValueAnimator; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.os.RemoteException; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.Display; import android.view.IRotationWatcher; import android.view.IWindowManager; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; import android.view.View; Loading @@ -55,6 +61,8 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; Loading @@ -73,9 +81,12 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { private ValueAnimator mShowHideBorderAnimator; private SurfaceControl.Transaction mTransaction; private TestableWindowManager mWindowManager; @Mock private IWindowManager mIWindowManager; @Before public void setUp() { MockitoAnnotations.initMocks(this); getInstrumentation().runOnMainSync(() -> mSurfaceControlViewHost = spy(new SurfaceControlViewHost(mContext, mContext.getDisplay(), new InputTransferToken(), "FullscreenMagnification"))); Loading @@ -88,9 +99,11 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { mShowHideBorderAnimator = spy(newNullTargetObjectAnimator()); mFullscreenMagnificationController = new FullscreenMagnificationController( mContext, mContext.getMainThreadHandler(), mContext.getMainExecutor(), mContext.getSystemService(AccessibilityManager.class), mContext.getSystemService(WindowManager.class), mIWindowManager, scvhSupplier, mTransaction, mShowHideBorderAnimator); Loading @@ -104,7 +117,8 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { } @Test public void enableFullscreenMagnification_visibleBorder() throws InterruptedException { public void enableFullscreenMagnification_visibleBorder() throws InterruptedException, RemoteException { CountDownLatch transactionCommittedLatch = new CountDownLatch(1); CountDownLatch animationEndLatch = new CountDownLatch(1); mTransaction.addTransactionCommittedListener( Loading @@ -119,17 +133,21 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { //Enable fullscreen magnification mFullscreenMagnificationController .onFullscreenMagnificationActivationChanged(true)); assertTrue("Failed to wait for transaction committed", transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS)); assertTrue("Failed to wait for animation to be finished", animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)); 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(mShowHideBorderAnimator).start(); verify(mIWindowManager) .watchRotation(any(IRotationWatcher.class), eq(Display.DEFAULT_DISPLAY)); assertThat(mSurfaceControlViewHost.getView().isVisibleToUser()).isTrue(); } @Test public void disableFullscreenMagnification_reverseAnimationAndReleaseScvh() throws InterruptedException { throws InterruptedException, RemoteException { CountDownLatch transactionCommittedLatch = new CountDownLatch(1); CountDownLatch enableAnimationEndLatch = new CountDownLatch(1); CountDownLatch disableAnimationEndLatch = new CountDownLatch(1); Loading @@ -149,11 +167,12 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { //Enable fullscreen magnification mFullscreenMagnificationController .onFullscreenMagnificationActivationChanged(true)); assertTrue("Failed to wait for transaction committed", transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS)); assertTrue("Failed to wait for enabling animation to be finished", enableAnimationEndLatch.await( ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertWithMessage("Failed to wait for transaction committed") .that(transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS)) .isTrue(); assertWithMessage("Failed to wait for enabling animation to be finished") .that(enableAnimationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)) .isTrue(); verify(mShowHideBorderAnimator).start(); getInstrumentation().runOnMainSync(() -> Loading @@ -161,11 +180,12 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { mFullscreenMagnificationController .onFullscreenMagnificationActivationChanged(false)); assertTrue("Failed to wait for disabling animation to be finished", disableAnimationEndLatch.await( ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertWithMessage("Failed to wait for disabling animation to be finished") .that(disableAnimationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)) .isTrue(); verify(mShowHideBorderAnimator).reverse(); verify(mSurfaceControlViewHost).release(); verify(mIWindowManager).removeRotationWatcher(any(IRotationWatcher.class)); } @Test Loading @@ -188,10 +208,12 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { () -> mFullscreenMagnificationController .onFullscreenMagnificationActivationChanged(true)); assertTrue("Failed to wait for transaction committed", transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS)); assertTrue("Failed to wait for animation to be finished", animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)); 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(mShowHideBorderAnimator).reverse(); } Loading @@ -212,10 +234,12 @@ public class FullscreenMagnificationControllerTest extends SysuiTestCase { //Enable fullscreen magnification mFullscreenMagnificationController .onFullscreenMagnificationActivationChanged(true)); assertTrue("Failed to wait for transaction committed", transactionCommittedLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS)); assertTrue("Failed to wait for animation to be finished", animationEndLatch.await(ANIMATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)); 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(); final Rect testWindowBounds = new Rect( mWindowManager.getCurrentWindowMetrics().getBounds()); testWindowBounds.set(testWindowBounds.left, testWindowBounds.top, Loading
packages/SystemUI/tests/src/com/android/systemui/accessibility/IMagnificationConnectionTest.java +6 −2 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import android.testing.TestableLooper; import android.view.Display; import android.view.IWindowManager; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IMagnificationConnection; import android.view.accessibility.IMagnificationConnectionCallback; Loading Loading @@ -99,6 +100,8 @@ public class IMagnificationConnectionTest extends SysuiTestCase { private SecureSettings mSecureSettings; @Mock private AccessibilityLogger mA11yLogger; @Mock private IWindowManager mIWindowManager; private IMagnificationConnection mIMagnificationConnection; private Magnification mMagnification; Loading @@ -117,9 +120,10 @@ public class IMagnificationConnectionTest extends SysuiTestCase { mTestableLooper = TestableLooper.get(this); assertNotNull(mTestableLooper); mMagnification = new Magnification(getContext(), mTestableLooper.getLooper(), getContext().getMainExecutor(), mCommandQueue, mTestableLooper.getLooper(), mContext.getMainExecutor(), mCommandQueue, mModeSwitchesController, mSysUiState, mOverviewProxyService, mSecureSettings, mDisplayTracker, getContext().getSystemService(DisplayManager.class), mA11yLogger); mDisplayTracker, getContext().getSystemService(DisplayManager.class), mA11yLogger, mIWindowManager); mMagnification.mWindowMagnificationControllerSupplier = new FakeWindowMagnificationControllerSupplier( mContext.getSystemService(DisplayManager.class)); Loading
packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java +5 −2 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import android.hardware.display.DisplayManager; import android.os.RemoteException; import android.testing.TestableLooper; import android.view.Display; import android.view.IWindowManager; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IMagnificationConnection; import android.view.accessibility.IMagnificationConnectionCallback; Loading Loading @@ -93,6 +94,8 @@ public class MagnificationTest extends SysuiTestCase { private MagnificationSettingsController mMagnificationSettingsController; @Mock private AccessibilityLogger mA11yLogger; @Mock private IWindowManager mIWindowManager; @Before public void setUp() throws Exception { Loading Loading @@ -122,10 +125,10 @@ public class MagnificationTest extends SysuiTestCase { mCommandQueue = new CommandQueue(getContext(), mDisplayTracker); mMagnification = new Magnification(getContext(), getContext().getMainThreadHandler(), getContext().getMainExecutor(), getContext().getMainThreadHandler(), mContext.getMainExecutor(), mCommandQueue, mModeSwitchesController, mSysUiState, mOverviewProxyService, mSecureSettings, mDisplayTracker, getContext().getSystemService(DisplayManager.class), mA11yLogger); getContext().getSystemService(DisplayManager.class), mA11yLogger, mIWindowManager); mMagnification.mWindowMagnificationControllerSupplier = new FakeControllerSupplier( mContext.getSystemService(DisplayManager.class), mWindowMagnificationController); mMagnification.mMagnificationSettingsSupplier = new FakeSettingsSupplier( Loading