Adds new magnificationController API: getCurrentMagnificationRegion, resetCurrentMagnification

See go/b200769372 - the legacy public methods
The legacy magnification controller methods of a11y service,
  getMagnificationRegion(),
  reset(),
will keep the behavior before that control
only full-screen magnification.

To make the a11y service able to control the actiavted
magnifier on the display, the service should use the
new public APIs,
 1. getCurrentMagnificationRegion(),
 2. resetCurrentMagnification(),
instead of the legacy APIs.

Bug: 210069654
Test: atest AccessibilityMagnificationTest,
   atest MagnificationProcessorTest,
   atest AbstractAccessibilityServiceConnectionTest,
Change-Id: I76bfee43cbb76a9aeec33574a8db18430903e08c
This commit is contained in:
mincheli
2021-12-15 00:50:31 +08:00
parent a75f5a9aed
commit 91443b10f7
8 changed files with 223 additions and 4 deletions

View File

@@ -3125,11 +3125,13 @@ package android.accessibilityservice {
method public void addListener(@NonNull android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, @Nullable android.os.Handler);
method public float getCenterX();
method public float getCenterY();
method @NonNull public android.graphics.Region getCurrentMagnificationRegion();
method @Nullable public android.accessibilityservice.MagnificationConfig getMagnificationConfig();
method @NonNull public android.graphics.Region getMagnificationRegion();
method public float getScale();
method public boolean removeListener(@NonNull android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
method public boolean reset(boolean);
method public boolean resetCurrentMagnification(boolean);
method public boolean setCenter(float, float, boolean);
method public boolean setMagnificationConfig(@NonNull android.accessibilityservice.MagnificationConfig, boolean);
method public boolean setScale(float, boolean);

View File

@@ -1503,6 +1503,12 @@ public abstract class AccessibilityService extends Service {
* {@link AccessibilityService#onServiceConnected()} has not yet been
* called) or the service has been disconnected, this method will
* return an empty region.
* </p>
* <p>
* <strong>Note:</strong> This legacy API gets the magnification region of full-screen
* magnification. To get the magnification region of the current controlling magnifier,
* use {@link #getCurrentMagnificationRegion()} instead.
* </p>
*
* @return the region of the screen currently active for magnification, or an empty region
* if magnification is not active.
@@ -1523,6 +1529,45 @@ public abstract class AccessibilityService extends Service {
return Region.obtain();
}
/**
* Returns the region of the screen currently active for magnification if the
* controlling magnification is {@link MagnificationConfig#MAGNIFICATION_MODE_FULLSCREEN}.
* Returns the region of screen projected on the magnification window if the
* controlling magnification is {@link MagnificationConfig#MAGNIFICATION_MODE_WINDOW}.
*
* <p>
* If the controlling mode is {@link MagnificationConfig#MAGNIFICATION_MODE_FULLSCREEN},
* the returned region will be empty if the magnification is
* not active. And the magnification is active if magnification gestures are enabled
* or if a service is running that can control magnification.
* </p><p>
* If the controlling mode is {@link MagnificationConfig#MAGNIFICATION_MODE_WINDOW},
* the returned region will be empty if the magnification is not activated.
* </p><p>
* <strong>Note:</strong> If the service is not yet connected (e.g.
* {@link AccessibilityService#onServiceConnected()} has not yet been
* called) or the service has been disconnected, this method will
* return an empty region.
* </p>
*
* @return the magnification region of the currently controlling magnification
*/
@NonNull
public Region getCurrentMagnificationRegion() {
final IAccessibilityServiceConnection connection =
AccessibilityInteractionClient.getInstance(mService).getConnection(
mService.mConnectionId);
if (connection != null) {
try {
return connection.getCurrentMagnificationRegion(mDisplayId);
} catch (RemoteException re) {
Log.w(LOG_TAG, "Failed to obtain the current magnified region", re);
re.rethrowFromSystemServer();
}
}
return Region.obtain();
}
/**
* Resets magnification scale and center to their default (e.g. no
* magnification) values.
@@ -1531,6 +1576,11 @@ public abstract class AccessibilityService extends Service {
* {@link AccessibilityService#onServiceConnected()} has not yet been
* called) or the service has been disconnected, this method will have
* no effect and return {@code false}.
* <p>
* <strong>Note:</strong> This legacy API reset full-screen magnification.
* To reset the current controlling magnifier, use
* {@link #resetCurrentMagnification(boolean)} ()} instead.
* </p>
*
* @param animate {@code true} to animate from the current scale and
* center or {@code false} to reset the scale and center
@@ -1552,6 +1602,36 @@ public abstract class AccessibilityService extends Service {
return false;
}
/**
* Resets magnification scale and center of the controlling magnification
* to their default (e.g. no magnification) values.
* <p>
* <strong>Note:</strong> If the service is not yet connected (e.g.
* {@link AccessibilityService#onServiceConnected()} has not yet been
* called) or the service has been disconnected, this method will have
* no effect and return {@code false}.
* </p>
*
* @param animate {@code true} to animate from the current scale and
* center or {@code false} to reset the scale and center
* immediately
* @return {@code true} on success, {@code false} on failure
*/
public boolean resetCurrentMagnification(boolean animate) {
final IAccessibilityServiceConnection connection =
AccessibilityInteractionClient.getInstance(mService).getConnection(
mService.mConnectionId);
if (connection != null) {
try {
return connection.resetCurrentMagnification(mDisplayId, animate);
} catch (RemoteException re) {
Log.w(LOG_TAG, "Failed to reset", re);
re.rethrowFromSystemServer();
}
}
return false;
}
/**
* Sets the {@link MagnificationConfig}. The service controls the magnification by
* setting the config.

View File

@@ -88,8 +88,12 @@ interface IAccessibilityServiceConnection {
Region getMagnificationRegion(int displayId);
Region getCurrentMagnificationRegion(int displayId);
boolean resetMagnification(int displayId, boolean animate);
boolean resetCurrentMagnification(int displayId, boolean animate);
boolean setMagnificationConfig(int displayId, in MagnificationConfig config, boolean animate);
void setMagnificationCallbackEnabled(int displayId, boolean enabled);

View File

@@ -120,10 +120,18 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon
return null;
}
public Region getCurrentMagnificationRegion(int displayId) {
return null;
}
public boolean resetMagnification(int displayId, boolean animate) {
return false;
}
public boolean resetCurrentMagnification(int displayId, boolean animate) {
return false;
}
public boolean setMagnificationConfig(int displayId,
@NonNull MagnificationConfig config, boolean animate) {
return false;

View File

@@ -1036,6 +1036,30 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
@Override
public Region getCurrentMagnificationRegion(int displayId) {
if (svcConnTracingEnabled()) {
logTraceSvcConn("getCurrentMagnificationRegion", "displayId=" + displayId);
}
synchronized (mLock) {
final Region region = Region.obtain();
if (!hasRightsToCurrentUserLocked()) {
return region;
}
MagnificationProcessor magnificationProcessor =
mSystemSupport.getMagnificationProcessor();
final long identity = Binder.clearCallingIdentity();
try {
magnificationProcessor.getCurrentMagnificationRegion(displayId,
region, mSecurityPolicy.canControlMagnification(this));
return region;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
@Override
public float getMagnificationCenterX(int displayId) {
if (svcConnTracingEnabled()) {
@@ -1102,6 +1126,31 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
}
}
@Override
public boolean resetCurrentMagnification(int displayId, boolean animate) {
if (svcConnTracingEnabled()) {
logTraceSvcConn("resetCurrentMagnification",
"displayId=" + displayId + ";animate=" + animate);
}
synchronized (mLock) {
if (!hasRightsToCurrentUserLocked()) {
return false;
}
if (!mSecurityPolicy.canControlMagnification(this)) {
return false;
}
}
final long identity = Binder.clearCallingIdentity();
try {
MagnificationProcessor magnificationProcessor =
mSystemSupport.getMagnificationProcessor();
return (magnificationProcessor.resetCurrentMagnification(displayId, animate)
|| !magnificationProcessor.isMagnifying(displayId));
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public boolean setMagnificationConfig(int displayId,
@NonNull MagnificationConfig config, boolean animate) {

View File

@@ -202,6 +202,36 @@ public class MagnificationProcessor {
}
}
/**
* Returns the region of the screen currently active for magnification if the
* controlling magnification is {@link MagnificationConfig#MAGNIFICATION_MODE_FULLSCREEN}.
* Returns the region of screen projected on the magnification window if the controlling
* magnification is {@link MagnificationConfig#MAGNIFICATION_MODE_WINDOW}.
* <p>
* If the controlling mode is {@link MagnificationConfig#MAGNIFICATION_MODE_FULLSCREEN},
* the returned region will be empty if the magnification is
* not active. And the magnification is active if magnification gestures are enabled
* or if a service is running that can control magnification.
* </p><p>
* If the controlling mode is {@link MagnificationConfig#MAGNIFICATION_MODE_WINDOW},
* the returned region will be empty if the magnification is not activated.
* </p>
*
* @param displayId The logical display id
* @param outRegion the region to populate
* @param canControlMagnification Whether the service can control magnification
*/
public void getCurrentMagnificationRegion(int displayId, @NonNull Region outRegion,
boolean canControlMagnification) {
int currentMode = getControllingMode(displayId);
if (currentMode == MAGNIFICATION_MODE_FULLSCREEN) {
getFullscreenMagnificationRegion(displayId, outRegion, canControlMagnification);
} else if (currentMode == MAGNIFICATION_MODE_WINDOW) {
mController.getWindowMagnificationMgr().getMagnificationSourceBounds(displayId,
outRegion);
}
}
/**
* Returns the magnification bounds of full-screen magnification on the given display.
*
@@ -224,8 +254,8 @@ public class MagnificationProcessor {
}
/**
* Resets the current magnification on the given display. The reset mode could be
* full-screen or window if it is activated.
* Resets the controlling magnifier on the given display.
* For resetting window magnifier, it disables the magnifier by setting the scale to 1.
*
* @param displayId The logical display id.
* @param animate {@code true} to animate the transition, {@code false}

View File

@@ -594,6 +594,20 @@ public class AbstractAccessibilityServiceConnectionTest {
assertThat(result.isEmpty(), is(true));
}
@Test
public void getCurrentMagnificationRegion_returnRegion() {
final int displayId = 1;
final Region region = new Region(10, 20, 100, 200);
doAnswer((invocation) -> {
((Region) invocation.getArguments()[1]).set(region);
return null;
}).when(mMockMagnificationProcessor).getCurrentMagnificationRegion(eq(displayId), any(),
anyBoolean());
final Region result = mServiceConnection.getCurrentMagnificationRegion(displayId);
assertEquals(result, region);
}
@Test
public void getMagnificationCenterX_serviceNotBelongCurrentUser_returnZero() {
final int displayId = 1;

View File

@@ -183,6 +183,38 @@ public class MagnificationProcessorTest {
verify(mMockFullScreenMagnificationController).unregister(TEST_DISPLAY);
}
@Test
public void getCurrentMagnificationRegion_windowModeActivated_returnRegion() {
final Region region = new Region(10, 20, 100, 200);
setMagnificationActivated(TEST_DISPLAY, MAGNIFICATION_MODE_WINDOW);
doAnswer((invocation) -> {
((Region) invocation.getArguments()[1]).set(region);
return null;
}).when(mMockWindowMagnificationManager).getMagnificationSourceBounds(eq(TEST_DISPLAY),
any());
final Region result = new Region();
mMagnificationProcessor.getCurrentMagnificationRegion(TEST_DISPLAY,
result, /* canControlMagnification= */true);
assertEquals(region, result);
}
@Test
public void getCurrentMagnificationRegion_fullscreenModeActivated_returnRegion() {
final Region region = new Region(10, 20, 100, 200);
setMagnificationActivated(TEST_DISPLAY, MAGNIFICATION_MODE_FULLSCREEN);
doAnswer((invocation) -> {
((Region) invocation.getArguments()[1]).set(region);
return null;
}).when(mMockFullScreenMagnificationController).getMagnificationRegion(eq(TEST_DISPLAY),
any());
final Region result = new Region();
mMagnificationProcessor.getCurrentMagnificationRegion(TEST_DISPLAY,
result, /* canControlMagnification= */true);
assertEquals(region, result);
}
@Test
public void getMagnificationCenterX_fullscreenModeNotRegistered_shouldRegisterThenUnregister() {
final MagnificationConfig config = new MagnificationConfig.Builder()
@@ -222,7 +254,7 @@ public class MagnificationProcessorTest {
}
@Test
public void reset_fullscreenMagnificationActivated() {
public void resetFullscreenMagnification_fullscreenMagnificationActivated() {
setMagnificationActivated(TEST_DISPLAY, MAGNIFICATION_MODE_FULLSCREEN);
mMagnificationProcessor.resetFullscreenMagnification(TEST_DISPLAY, /* animate= */false);
@@ -231,7 +263,7 @@ public class MagnificationProcessorTest {
}
@Test
public void reset_windowMagnificationActivated() {
public void resetCurrentMagnification_windowMagnificationActivated() {
setMagnificationActivated(TEST_DISPLAY, MAGNIFICATION_MODE_WINDOW);
mMagnificationProcessor.resetCurrentMagnification(TEST_DISPLAY, /* animate= */false);