Merge "Notifies magnification change for the transitioning target mode" into tm-dev

This commit is contained in:
Minche Li
2022-04-12 01:10:41 +00:00
committed by Android (Google) Code Review
5 changed files with 264 additions and 33 deletions

View File

@@ -353,6 +353,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mSourceBounds.setEmpty(); mSourceBounds.setEmpty();
updateSystemUIStateIfNeeded(); updateSystemUIStateIfNeeded();
mContext.unregisterComponentCallbacks(this); mContext.unregisterComponentCallbacks(this);
// Notify source bounds empty when magnification is deleted.
mWindowMagnifierCallback.onSourceBoundsChanged(mDisplayId, new Rect());
} }
@Override @Override

View File

@@ -292,6 +292,22 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
assertFalse(hasMagnificationOverlapFlag()); assertFalse(hasMagnificationOverlapFlag());
} }
@Test
public void deleteWindowMagnification_notifySourceBoundsChanged() {
mInstrumentation.runOnMainSync(
() -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
Float.NaN,
Float.NaN));
mInstrumentation.runOnMainSync(
() -> mWindowMagnificationController.deleteWindowMagnification());
// The first time is for notifying magnification enabled and the second time is for
// notifying magnification disabled.
verify(mWindowMagnifierCallback, times(2)).onSourceBoundsChanged(
(eq(mContext.getDisplayId())), any());
}
@Test @Test
public void moveMagnifier_schedulesFrame() { public void moveMagnifier_schedulesFrame() {
mInstrumentation.runOnMainSync(() -> { mInstrumentation.runOnMainSync(() -> {

View File

@@ -356,13 +356,6 @@ public class FullScreenMagnificationController implements
mSpecAnimationBridge, spec, animationCallback); mSpecAnimationBridge, spec, animationCallback);
mControllerCtx.getHandler().sendMessage(m); mControllerCtx.getHandler().sendMessage(m);
} }
final boolean lastMagnificationActivated = mMagnificationActivated;
mMagnificationActivated = spec.scale > 1.0f;
if (mMagnificationActivated != lastMagnificationActivated) {
mMagnificationInfoChangedCallback.onFullScreenMagnificationActivationState(
mDisplayId, mMagnificationActivated);
}
} }
/** /**
@@ -376,9 +369,17 @@ public class FullScreenMagnificationController implements
@GuardedBy("mLock") @GuardedBy("mLock")
void onMagnificationChangedLocked() { void onMagnificationChangedLocked() {
final float scale = getScale();
final boolean lastMagnificationActivated = mMagnificationActivated;
mMagnificationActivated = scale > 1.0f;
if (mMagnificationActivated != lastMagnificationActivated) {
mMagnificationInfoChangedCallback.onFullScreenMagnificationActivationState(
mDisplayId, mMagnificationActivated);
}
final MagnificationConfig config = new MagnificationConfig.Builder() final MagnificationConfig config = new MagnificationConfig.Builder()
.setMode(MAGNIFICATION_MODE_FULLSCREEN) .setMode(MAGNIFICATION_MODE_FULLSCREEN)
.setScale(getScale()) .setScale(scale)
.setCenterX(getCenterX()) .setCenterX(getCenterX())
.setCenterY(getCenterY()).build(); .setCenterY(getCenterY()).build();
mMagnificationInfoChangedCallback.onFullScreenMagnificationChanged(mDisplayId, mMagnificationInfoChangedCallback.onFullScreenMagnificationChanged(mDisplayId,

View File

@@ -16,6 +16,7 @@
package com.android.server.accessibility.magnification; package com.android.server.accessibility.magnification;
import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_FULLSCREEN;
import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_WINDOW; import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_WINDOW;
import static android.content.pm.PackageManager.FEATURE_WINDOW_MAGNIFICATION; import static android.content.pm.PackageManager.FEATURE_WINDOW_MAGNIFICATION;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
@@ -111,6 +112,15 @@ public class MagnificationController implements WindowMagnificationManager.Callb
@GuardedBy("mLock") @GuardedBy("mLock")
private final SparseLongArray mFullScreenModeEnabledTimeArray = new SparseLongArray(); private final SparseLongArray mFullScreenModeEnabledTimeArray = new SparseLongArray();
/**
* The transitioning magnification modes on the displays. The controller notifies
* magnification change depending on the target config mode.
* If the target mode is null, it means the config mode of the display is not
* transitioning.
*/
@GuardedBy("mLock")
private final SparseArray<Integer> mTransitionModes = new SparseArray();
@GuardedBy("mLock") @GuardedBy("mLock")
private final SparseArray<WindowManagerInternal.AccessibilityControllerInternal private final SparseArray<WindowManagerInternal.AccessibilityControllerInternal
.UiChangesForAccessibilityCallbacks> mAccessibilityCallbacksDelegateArray = .UiChangesForAccessibilityCallbacks> mAccessibilityCallbacksDelegateArray =
@@ -213,6 +223,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
final PointF currentCenter = getCurrentMagnificationCenterLocked(displayId, targetMode); final PointF currentCenter = getCurrentMagnificationCenterLocked(displayId, targetMode);
final DisableMagnificationCallback animationCallback = final DisableMagnificationCallback animationCallback =
getDisableMagnificationEndRunnableLocked(displayId); getDisableMagnificationEndRunnableLocked(displayId);
if (currentCenter == null && animationCallback == null) { if (currentCenter == null && animationCallback == null) {
transitionCallBack.onResult(displayId, true); transitionCallBack.onResult(displayId, true);
return; return;
@@ -233,6 +244,9 @@ public class MagnificationController implements WindowMagnificationManager.Callb
transitionCallBack.onResult(displayId, true); transitionCallBack.onResult(displayId, true);
return; return;
} }
setTransitionState(displayId, targetMode);
final FullScreenMagnificationController screenMagnificationController = final FullScreenMagnificationController screenMagnificationController =
getFullScreenMagnificationController(); getFullScreenMagnificationController();
final WindowMagnificationManager windowMagnificationMgr = getWindowMagnificationMgr(); final WindowMagnificationManager windowMagnificationMgr = getWindowMagnificationMgr();
@@ -286,19 +300,21 @@ public class MagnificationController implements WindowMagnificationManager.Callb
Slog.w(TAG, "Discard previous animation request"); Slog.w(TAG, "Discard previous animation request");
animationCallback.setExpiredAndRemoveFromListLocked(); animationCallback.setExpiredAndRemoveFromListLocked();
} }
final FullScreenMagnificationController screenMagnificationController = final FullScreenMagnificationController screenMagnificationController =
getFullScreenMagnificationController(); getFullScreenMagnificationController();
final WindowMagnificationManager windowMagnificationMgr = getWindowMagnificationMgr(); final WindowMagnificationManager windowMagnificationMgr = getWindowMagnificationMgr();
final float targetScale = Float.isNaN(config.getScale()) final float targetScale = Float.isNaN(config.getScale())
? getTargetModeScaleFromCurrentMagnification(displayId, targetMode) ? getTargetModeScaleFromCurrentMagnification(displayId, targetMode)
: config.getScale(); : config.getScale();
if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) { try {
setTransitionState(displayId, targetMode);
if (targetMode == MAGNIFICATION_MODE_WINDOW) {
screenMagnificationController.reset(displayId, false); screenMagnificationController.reset(displayId, false);
windowMagnificationMgr.enableWindowMagnification(displayId, windowMagnificationMgr.enableWindowMagnification(displayId,
targetScale, magnificationCenter.x, magnificationCenter.y, targetScale, magnificationCenter.x, magnificationCenter.y,
animate ? STUB_ANIMATION_CALLBACK : null, id); animate ? STUB_ANIMATION_CALLBACK : null, id);
} else if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) { } else if (targetMode == MAGNIFICATION_MODE_FULLSCREEN) {
windowMagnificationMgr.disableWindowMagnification(displayId, false, null); windowMagnificationMgr.disableWindowMagnification(displayId, false, null);
if (!screenMagnificationController.isRegistered(displayId)) { if (!screenMagnificationController.isRegistered(displayId)) {
screenMagnificationController.register(displayId); screenMagnificationController.register(displayId);
@@ -307,6 +323,29 @@ public class MagnificationController implements WindowMagnificationManager.Callb
magnificationCenter.x, magnificationCenter.y, animate, magnificationCenter.x, magnificationCenter.y, animate,
id); id);
} }
} finally {
// Reset transition state after enabling target mode.
setTransitionState(displayId, null);
}
}
}
/**
* Sets magnification config mode transition state. Called when the mode transition starts and
* ends. If the targetMode and the display id are null, it resets all
* the transition state.
*
* @param displayId The logical display id
* @param targetMode The transition target mode. It is not transitioning, if the target mode
* is set null
*/
private void setTransitionState(Integer displayId, Integer targetMode) {
synchronized (mLock) {
if (targetMode == null && displayId == null) {
mTransitionModes.clear();
} else {
mTransitionModes.put(displayId, targetMode);
}
} }
} }
@@ -413,6 +452,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
@Override @Override
public void onSourceBoundsChanged(int displayId, Rect bounds) { public void onSourceBoundsChanged(int displayId, Rect bounds) {
if (shouldNotifyMagnificationChange(displayId, MAGNIFICATION_MODE_WINDOW)) {
final MagnificationConfig config = new MagnificationConfig.Builder() final MagnificationConfig config = new MagnificationConfig.Builder()
.setMode(MAGNIFICATION_MODE_WINDOW) .setMode(MAGNIFICATION_MODE_WINDOW)
.setScale(getWindowMagnificationMgr().getScale(displayId)) .setScale(getWindowMagnificationMgr().getScale(displayId))
@@ -420,12 +460,50 @@ public class MagnificationController implements WindowMagnificationManager.Callb
.setCenterY(bounds.exactCenterY()).build(); .setCenterY(bounds.exactCenterY()).build();
mAms.notifyMagnificationChanged(displayId, new Region(bounds), config); mAms.notifyMagnificationChanged(displayId, new Region(bounds), config);
} }
}
@Override @Override
public void onFullScreenMagnificationChanged(int displayId, @NonNull Region region, public void onFullScreenMagnificationChanged(int displayId, @NonNull Region region,
@NonNull MagnificationConfig config) { @NonNull MagnificationConfig config) {
if (shouldNotifyMagnificationChange(displayId, MAGNIFICATION_MODE_FULLSCREEN)) {
mAms.notifyMagnificationChanged(displayId, region, config); mAms.notifyMagnificationChanged(displayId, region, config);
} }
}
/**
* Should notify magnification change for the given display under the conditions below
*
* <ol>
* <li> 1. No mode transitioning and the change mode is active. </li>
* <li> 2. No mode transitioning and all the modes are inactive. </li>
* <li> 3. It is mode transitioning and the change mode is the transition mode. </li>
* </ol>
*
* @param displayId The logical display id
* @param changeMode The mode that has magnification spec change
*/
private boolean shouldNotifyMagnificationChange(int displayId, int changeMode) {
synchronized (mLock) {
final boolean fullScreenMagnifying = mFullScreenMagnificationController != null
&& mFullScreenMagnificationController.isMagnifying(displayId);
final boolean windowEnabled = mWindowMagnificationMgr != null
&& mWindowMagnificationMgr.isWindowMagnifierEnabled(displayId);
final Integer transitionMode = mTransitionModes.get(displayId);
if (((changeMode == MAGNIFICATION_MODE_FULLSCREEN && fullScreenMagnifying)
|| (changeMode == MAGNIFICATION_MODE_WINDOW && windowEnabled))
&& (transitionMode == null)) {
return true;
}
if ((!fullScreenMagnifying && !windowEnabled)
&& (transitionMode == null)) {
return true;
}
if (transitionMode != null && changeMode == transitionMode) {
return true;
}
}
return false;
}
private void disableFullScreenMagnificationIfNeeded(int displayId) { private void disableFullScreenMagnificationIfNeeded(int displayId) {
final FullScreenMagnificationController fullScreenMagnificationController = final FullScreenMagnificationController fullScreenMagnificationController =
@@ -740,9 +818,32 @@ public class MagnificationController implements WindowMagnificationManager.Callb
return; return;
} }
setExpiredAndRemoveFromListLocked(); setExpiredAndRemoveFromListLocked();
setTransitionState(mDisplayId, null);
if (success) { if (success) {
adjustCurrentCenterIfNeededLocked(); adjustCurrentCenterIfNeededLocked();
applyMagnificationModeLocked(mTargetMode); applyMagnificationModeLocked(mTargetMode);
} else {
// Notify magnification change if magnification is inactive when the
// transition is failed. This is for the failed transition from
// full-screen to window mode. Disable magnification callback helps to send
// magnification inactive change since FullScreenMagnificationController
// would not notify magnification change if the spec is not changed.
final FullScreenMagnificationController screenMagnificationController =
getFullScreenMagnificationController();
if (mCurrentMode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
&& !screenMagnificationController.isMagnifying(mDisplayId)) {
MagnificationConfig.Builder configBuilder =
new MagnificationConfig.Builder();
Region region = new Region();
configBuilder.setMode(MAGNIFICATION_MODE_FULLSCREEN)
.setScale(screenMagnificationController.getScale(mDisplayId))
.setCenterX(screenMagnificationController.getCenterX(mDisplayId))
.setCenterY(screenMagnificationController.getCenterY(mDisplayId));
screenMagnificationController.getMagnificationRegion(mDisplayId,
region);
mAms.notifyMagnificationChanged(mDisplayId, region, configBuilder.build());
}
} }
updateMagnificationButton(mDisplayId, mTargetMode); updateMagnificationButton(mDisplayId, mTargetMode);
if (mTransitionCallBack != null) { if (mTransitionCallBack != null) {
@@ -770,6 +871,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
return; return;
} }
setExpiredAndRemoveFromListLocked(); setExpiredAndRemoveFromListLocked();
setTransitionState(mDisplayId, null);
applyMagnificationModeLocked(mCurrentMode); applyMagnificationModeLocked(mCurrentMode);
updateMagnificationButton(mDisplayId, mCurrentMode); updateMagnificationButton(mDisplayId, mCurrentMode);
if (mTransitionCallBack != null) { if (mTransitionCallBack != null) {

View File

@@ -197,6 +197,31 @@ public class MagnificationControllerTest {
assertEquals(MAGNIFIED_CENTER_Y, mWindowMagnificationManager.getCenterY(TEST_DISPLAY), 0); assertEquals(MAGNIFIED_CENTER_Y, mWindowMagnificationManager.getCenterY(TEST_DISPLAY), 0);
} }
@Test
public void transitionToWindowModeFailedByReset_fullScreenMagnifying_notifyTransitionFailed()
throws RemoteException {
setMagnificationEnabled(MODE_FULLSCREEN);
mMagnificationController.transitionMagnificationModeLocked(TEST_DISPLAY,
MODE_WINDOW,
mTransitionCallBack);
verify(mScreenMagnificationController).reset(eq(TEST_DISPLAY),
mCallbackArgumentCaptor.capture());
// The transition is interrupted and failed by calling reset.
mCallbackArgumentCaptor.getValue().onResult(false);
verify(mTransitionCallBack).onResult(TEST_DISPLAY, false);
final ArgumentCaptor<MagnificationConfig> configCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
// The first time is for notifying full-screen enabled and the second time is for notifying
// the target mode transitions failed.
verify(mService, times(2)).notifyMagnificationChanged(eq(TEST_DISPLAY), any(Region.class),
configCaptor.capture());
final MagnificationConfig actualConfig = configCaptor.getValue();
assertEquals(MODE_FULLSCREEN, actualConfig.getMode(), 0);
assertEquals(1.0f, actualConfig.getScale(), 0);
}
@Test @Test
public void transitionToWindowMode_disablingWindowMode_enablingWindowWithFormerCenter() public void transitionToWindowMode_disablingWindowMode_enablingWindowWithFormerCenter()
throws RemoteException { throws RemoteException {
@@ -478,6 +503,92 @@ public class MagnificationControllerTest {
assertEquals(config.getScale(), actualConfig.getScale(), 0); assertEquals(config.getScale(), actualConfig.getScale(), 0);
} }
@Test
public void transitionMagnificationMode_windowEnabled_notifyTargetMagnificationChanged()
throws RemoteException {
setMagnificationEnabled(MODE_WINDOW);
mMagnificationController.transitionMagnificationModeLocked(TEST_DISPLAY,
MODE_FULLSCREEN, mTransitionCallBack);
mMockConnection.invokeCallbacks();
final ArgumentCaptor<MagnificationConfig> configCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
// The first time is for notifying window enabled and the second time is for notifying
// the target mode transitions.
verify(mService, times(2)).notifyMagnificationChanged(eq(TEST_DISPLAY), any(Region.class),
configCaptor.capture());
final MagnificationConfig actualConfig = configCaptor.getValue();
assertEquals(MODE_FULLSCREEN, actualConfig.getMode(), 0);
}
@Test
public void transitionConfigMode_windowEnabled_notifyTargetMagnificationChanged()
throws RemoteException {
setMagnificationEnabled(MODE_WINDOW);
final MagnificationConfig config = obtainMagnificationConfig(MODE_FULLSCREEN);
mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
config, true, TEST_SERVICE_ID);
mMockConnection.invokeCallbacks();
final ArgumentCaptor<MagnificationConfig> configCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
// The first time is for notifying window enabled and the second time is for notifying
// the target mode transitions.
verify(mService, times(2)).notifyMagnificationChanged(eq(TEST_DISPLAY), any(Region.class),
configCaptor.capture());
final MagnificationConfig actualConfig = configCaptor.getValue();
assertEquals(config.getCenterX(), actualConfig.getCenterX(), 0);
assertEquals(config.getCenterY(), actualConfig.getCenterY(), 0);
assertEquals(config.getScale(), actualConfig.getScale(), 0);
}
@Test
public void transitionMagnificationMode_fullScreenEnabled_notifyTargetMagnificationChanged()
throws RemoteException {
setMagnificationEnabled(MODE_FULLSCREEN);
mMagnificationController.transitionMagnificationModeLocked(TEST_DISPLAY,
MODE_WINDOW, mTransitionCallBack);
verify(mScreenMagnificationController).reset(eq(TEST_DISPLAY),
mCallbackArgumentCaptor.capture());
mCallbackArgumentCaptor.getValue().onResult(true);
mMockConnection.invokeCallbacks();
final ArgumentCaptor<MagnificationConfig> configCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
// The first time is for notifying full-screen enabled and the second time is for notifying
// the target mode transitions.
verify(mService, times(2)).notifyMagnificationChanged(eq(TEST_DISPLAY), any(Region.class),
configCaptor.capture());
final MagnificationConfig actualConfig = configCaptor.getValue();
assertEquals(MODE_WINDOW, actualConfig.getMode(), 0);
}
@Test
public void transitionConfigMode_fullScreenEnabled_notifyTargetMagnificationChanged()
throws RemoteException {
setMagnificationEnabled(MODE_FULLSCREEN);
final MagnificationConfig config = obtainMagnificationConfig(MODE_WINDOW);
mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
config, true, TEST_SERVICE_ID);
mMockConnection.invokeCallbacks();
final ArgumentCaptor<MagnificationConfig> configCaptor = ArgumentCaptor.forClass(
MagnificationConfig.class);
// The first time is for notifying full-screen enabled and the second time is for notifying
// the target mode transitions.
verify(mService, times(2)).notifyMagnificationChanged(eq(TEST_DISPLAY), any(Region.class),
configCaptor.capture());
final MagnificationConfig actualConfig = configCaptor.getValue();
assertEquals(config.getCenterX(), actualConfig.getCenterX(), 0);
assertEquals(config.getCenterY(), actualConfig.getCenterY(), 0);
assertEquals(config.getScale(), actualConfig.getScale(), 0);
}
@Test @Test
public void onAccessibilityActionPerformed_magnifierEnabled_showMagnificationButton() public void onAccessibilityActionPerformed_magnifierEnabled_showMagnificationButton()
throws RemoteException { throws RemoteException {
@@ -743,7 +854,7 @@ public class MagnificationControllerTest {
} }
@Test @Test
public void disableWindowMode_windowModeInActive_removeMagnificationButton() public void disableWindowMode_windowEnabled_removeMagnificationButton()
throws RemoteException { throws RemoteException {
setMagnificationEnabled(MODE_WINDOW); setMagnificationEnabled(MODE_WINDOW);
@@ -753,7 +864,7 @@ public class MagnificationControllerTest {
} }
@Test @Test
public void onFullScreenDeactivated_fullscreenModeInActive_removeMagnificationButton() public void onFullScreenDeactivated_fullScreenEnabled_removeMagnificationButton()
throws RemoteException { throws RemoteException {
setMagnificationEnabled(MODE_FULLSCREEN); setMagnificationEnabled(MODE_FULLSCREEN);
mScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY, mScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY,
@@ -766,7 +877,7 @@ public class MagnificationControllerTest {
} }
@Test @Test
public void transitionToFullScreenMode_fullscreenModeInActive_showMagnificationButton() public void transitionToFullScreenMode_windowEnabled_showMagnificationButton()
throws RemoteException { throws RemoteException {
setMagnificationEnabled(MODE_WINDOW); setMagnificationEnabled(MODE_WINDOW);
@@ -779,7 +890,7 @@ public class MagnificationControllerTest {
} }
@Test @Test
public void transitionToWindow_fullscreenModeInActive_showMagnificationButton() public void transitionToWindow_fullScreenEnabled_showMagnificationButton()
throws RemoteException { throws RemoteException {
setMagnificationEnabled(MODE_FULLSCREEN); setMagnificationEnabled(MODE_FULLSCREEN);
@@ -1018,7 +1129,6 @@ public class MagnificationControllerTest {
reset(); reset();
} }
final MagnificationConfig config = new MagnificationConfig.Builder().setMode( final MagnificationConfig config = new MagnificationConfig.Builder().setMode(
MODE_FULLSCREEN).setScale(mScale).setCenterX(mCenterX).setCenterY( MODE_FULLSCREEN).setScale(mScale).setCenterX(mCenterX).setCenterY(
mCenterY).build(); mCenterY).build();