diff --git a/core/api/current.txt b/core/api/current.txt index 565928dfa9870..cddb6ff95a51d 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -3131,11 +3131,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); diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index d3e7c159b73a0..479e6bf594bab 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -1500,6 +1500,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. + *
+ *+ * Note: 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. + *
* * @return the region of the screen currently active for magnification, or an empty region * if magnification is not active. @@ -1520,6 +1526,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}. + * + *+ * 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. + *
+ * If the controlling mode is {@link MagnificationConfig#MAGNIFICATION_MODE_WINDOW}, + * the returned region will be empty if the magnification is not activated. + *
+ * Note: 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. + *
+ * + * @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. @@ -1528,6 +1573,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}. + *+ * Note: This legacy API reset full-screen magnification. + * To reset the current controlling magnifier, use + * {@link #resetCurrentMagnification(boolean)} ()} instead. + *
* * @param animate {@code true} to animate from the current scale and * center or {@code false} to reset the scale and center @@ -1549,6 +1599,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. + *+ * Note: 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}. + *
+ * + * @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. diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl index 7d76bbf350814..2cc15b40106be 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl @@ -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); diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java index 62d0b2e0b52fd..02e5942a3544f 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java @@ -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; diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 487eb553d58e6..e93ac47b19402 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -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) { diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java index 40f77b04d5de4..8f15d5cf3e3d3 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java @@ -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}. + *+ * 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. + *
+ * If the controlling mode is {@link MagnificationConfig#MAGNIFICATION_MODE_WINDOW}, + * the returned region will be empty if the magnification is not activated. + *
+ * + * @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} diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java index d18030f10603d..97ebdd4ad7fac 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java @@ -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; diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java index 99d6c2af6f75c..c4040b405d19a 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java @@ -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);