diff --git a/api/current.txt b/api/current.txt index 4dfbe63456a29..6fdd1bcb9866f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2699,7 +2699,7 @@ package android.accessibilityservice { method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler); method public float getCenterX(); method public float getCenterY(); - method public android.graphics.Region getMagnifiedRegion(); + method public android.graphics.Region getMagnificationRegion(); method public float getScale(); method public boolean removeListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener); method public boolean reset(boolean); diff --git a/api/system-current.txt b/api/system-current.txt index 3344b52e22376..41b73ebf344be 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -2810,7 +2810,7 @@ package android.accessibilityservice { method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler); method public float getCenterX(); method public float getCenterY(); - method public android.graphics.Region getMagnifiedRegion(); + method public android.graphics.Region getMagnificationRegion(); method public float getScale(); method public boolean removeListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener); method public boolean reset(boolean); diff --git a/api/test-current.txt b/api/test-current.txt index a0ca0f4447ecc..d40d0b8d4e3db 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -2699,7 +2699,7 @@ package android.accessibilityservice { method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler); method public float getCenterX(); method public float getCenterY(); - method public android.graphics.Region getMagnifiedRegion(); + method public android.graphics.Region getMagnificationRegion(); method public float getScale(); method public boolean removeListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener); method public boolean reset(boolean); diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 56728ad881e13..8b277b2a12ea4 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -925,18 +925,25 @@ public abstract class AccessibilityService extends Service { } /** - * Returns the region of the screen currently being magnified. If - * magnification is not enabled, the returned region will be empty. + * Returns the region of the screen currently active for magnification. Changes to + * magnification scale and center only affect this portion of the screen. The rest of the + * screen, for example input methods, cannot be magnified. This region is relative to the + * unscaled screen and is independent of the scale and center point. + *
+ * The returned region will be empty if magnification is not active. Magnification is active + * if magnification gestures are enabled or if a service is running that can control + * magnification. *
* 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 screen-relative bounds of the magnified region + * @return the region of the screen currently active for magnification, or an empty region + * if magnification is not active. */ @NonNull - public Region getMagnifiedRegion() { + public Region getMagnificationRegion() { final IAccessibilityServiceConnection connection = AccessibilityInteractionClient.getInstance().getConnection( mService.mConnectionId); @@ -1049,11 +1056,12 @@ public abstract class AccessibilityService extends Service { * Called when the magnified region, scale, or center changes. * * @param controller the magnification controller - * @param region the new magnified region, may be empty if - * magnification is not enabled (e.g. scale is 1) + * @param region the magnification region * @param scale the new scale - * @param centerX the new X coordinate around which magnification is focused - * @param centerY the new Y coordinate around which magnification is focused + * @param centerX the new X coordinate, in unscaled coordinates, around which + * magnification is focused + * @param centerY the new Y coordinate, in unscaled coordinates, around which + * magnification is focused */ void onMagnificationChanged(@NonNull MagnificationController controller, @NonNull Region region, float scale, float centerX, float centerY); diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java index 3ad730b085904..4b188c4e35c1b 100644 --- a/core/java/android/view/WindowManagerInternal.java +++ b/core/java/android/view/WindowManagerInternal.java @@ -54,13 +54,12 @@ public abstract class WindowManagerInternal { public interface MagnificationCallbacks { /** - * Called when the bounds of the screen content that is magnified changed. - * Note that not the entire screen is magnified. + * Called when the region where magnification operates changes. Note that this isn't the + * entire screen. For example, IMEs are not magnified. * - * @param magnifiedBounds the currently magnified region - * @param availableBounds the region available for magnification + * @param magnificationRegion the current magnification region */ - public void onMagnifiedBoundsChanged(Region magnifiedBounds, Region availableBounds); + public void onMagnificationRegionChanged(Region magnificationRegion); /** * Called when an application requests a rectangle on the screen to allow @@ -158,13 +157,11 @@ public abstract class WindowManagerInternal { public abstract void setMagnificationSpec(MagnificationSpec spec); /** - * Obtains the magnified and available regions. + * Obtains the magnification regions. * - * @param outMagnified the currently magnified region - * @param outAvailable the region available for magnification + * @param magnificationRegion the current magnification region */ - public abstract void getMagnificationRegions(@NonNull Region outMagnified, - @NonNull Region outAvailable); + public abstract void getMagnificationRegion(@NonNull Region magnificationRegion); /** * Gets the magnification and translation applied to a window given its token. diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 1b85016333c88..fc2e95dc7ca5b 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -151,7 +151,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private static final int WINDOW_ID_UNKNOWN = -1; - private static int sIdCounter = 0; + // Each service has an ID. Also provide one for magnification gesture handling + public static final int MAGNIFICATION_GESTURE_HANDLER_ID = 0; + + private static int sIdCounter = MAGNIFICATION_GESTURE_HANDLER_ID + 1; private static int sNextWindowId; @@ -183,8 +186,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private MagnificationController mMagnificationController; - private boolean mUnregisterMagnificationOnReset; - private InteractionBridge mInteractionBridge; private AlertDialog mEnableTouchExplorationDialog; @@ -784,11 +785,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { float scale, float centerX, float centerY) { synchronized (mLock) { notifyMagnificationChangedLocked(region, scale, centerX, centerY); - - if (mUnregisterMagnificationOnReset && scale == 1.0f) { - mUnregisterMagnificationOnReset = false; - mMagnificationController.unregister(); - } } } @@ -1736,25 +1732,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } private void updateMagnificationLocked(UserState userState) { - final int userId = userState.mUserId; - if (userId == mCurrentUserId && mMagnificationController != null) { - if (userState.mIsDisplayMagnificationEnabled || - userHasMagnificationServicesLocked(userState)) { - mMagnificationController.setUserId(userState.mUserId); - } else { - // If the user no longer has any magnification-controlling - // services and is not using magnification gestures, then - // reset the state to normal. - if (mMagnificationController.resetIfNeeded(true)) { - // Animations are still running, so wait until we receive a - // callback verifying that we've reset magnification. - mUnregisterMagnificationOnReset = true; - } else { - mUnregisterMagnificationOnReset = false; - mMagnificationController.unregister(); - mMagnificationController = null; - } - } + if (userState.mUserId != mCurrentUserId) { + return; + } + + if (userState.mIsDisplayMagnificationEnabled || + userHasMagnificationServicesLocked(userState)) { + // Initialize the magnification controller if necessary + getMagnificationController(); + mMagnificationController.register(); + } else if (mMagnificationController != null) { + mMagnificationController.unregister(); } } @@ -2152,7 +2140,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { synchronized (mLock) { if (mMagnificationController == null) { mMagnificationController = new MagnificationController(mContext, this, mLock); - mMagnificationController.register(); mMagnificationController.setUserId(mCurrentUserId); } return mMagnificationController; @@ -2886,7 +2873,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { final long identity = Binder.clearCallingIdentity(); try { final Region region = Region.obtain(); - getMagnificationController().getMagnifiedRegion(region); + getMagnificationController().getMagnificationRegion(region); return region; } finally { Binder.restoreCallingIdentity(identity); @@ -2957,7 +2944,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { final long identity = Binder.clearCallingIdentity(); try { return getMagnificationController().setScaleAndCenter( - scale, centerX, centerY, animate); + scale, centerX, centerY, animate, mId); } finally { Binder.restoreCallingIdentity(identity); } @@ -3090,10 +3077,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { userState.mInstalledServices.remove(mAccessibilityServiceInfo); userState.mEnabledServices.remove(mComponentName); userState.destroyUiAutomationService(); - if (readConfigurationForUserStateLocked(userState)) { - onUserStateChangedLocked(userState); - } } + if (mId == getMagnificationController().getIdOfLastServiceToMagnify()) { + getMagnificationController().resetIfNeeded(true); + } + onUserStateChangedLocked(userState); } } diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java index f1b3722eed8ee..027b6e2c83e25 100644 --- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java @@ -17,6 +17,7 @@ package com.android.server.accessibility; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.os.SomeArgs; import com.android.server.LocalServices; @@ -60,6 +61,8 @@ class MagnificationController { private static final int DEFAULT_SCREEN_MAGNIFICATION_AUTO_UPDATE = 1; + private static final int INVALID_ID = -1; + private static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f; private static final float MIN_SCALE = 1.0f; @@ -80,9 +83,8 @@ class MagnificationController { */ private final MagnificationSpec mCurrentMagnificationSpec = MagnificationSpec.obtain(); - private final Region mMagnifiedRegion = Region.obtain(); - private final Region mAvailableRegion = Region.obtain(); - private final Rect mMagnifiedBounds = new Rect(); + private final Region mMagnificationRegion = Region.obtain(); + private final Rect mMagnificationBounds = new Rect(); private final Rect mTempRect = new Rect(); private final Rect mTempRect1 = new Rect(); @@ -97,35 +99,67 @@ class MagnificationController { private int mUserId; + private int mIdOfLastServiceToMagnify = INVALID_ID; + + // Flag indicating that we are registered with window manager. + private boolean mRegistered; + + private boolean mUnregisterPending; + public MagnificationController(Context context, AccessibilityManagerService ams, Object lock) { mAms = ams; mContentResolver = context.getContentResolver(); mScreenStateObserver = new ScreenStateObserver(context, this); mWindowStateObserver = new WindowStateObserver(context, this); - mSpecAnimationBridge = new SpecAnimationBridge(context); mLock = lock; + mSpecAnimationBridge = new SpecAnimationBridge(context, mLock); } /** - * Registers magnification-related observers. + * Start tracking the magnification region for services that control magnification and the + * magnification gesture handler. + * + * This tracking imposes a cost on the system, so we avoid tracking this data + * unless it's required. */ public void register() { - mScreenStateObserver.register(); - mWindowStateObserver.register(); - - // Obtain initial state. - mWindowStateObserver.getRegions(mMagnifiedRegion, mAvailableRegion); - mMagnifiedRegion.getBounds(mMagnifiedBounds); + synchronized (mLock) { + if (!mRegistered) { + mScreenStateObserver.register(); + mWindowStateObserver.register(); + mSpecAnimationBridge.setEnabled(true); + // Obtain initial state. + mWindowStateObserver.getMagnificationRegion(mMagnificationRegion); + mMagnificationRegion.getBounds(mMagnificationBounds); + mRegistered = true; + } + } } /** - * Unregisters magnification-related observers. + * Stop requiring tracking the magnification region. We may remain registered while we + * reset magnification. */ public void unregister() { - mSpecAnimationBridge.cancel(); + synchronized (mLock) { + if (!isMagnifying()) { + unregisterInternalLocked(); + } else { + mUnregisterPending = true; + resetLocked(true); + } + } + } - mScreenStateObserver.unregister(); - mWindowStateObserver.unregister(); + private void unregisterInternalLocked() { + if (mRegistered) { + mSpecAnimationBridge.setEnabled(false); + mScreenStateObserver.unregister(); + mWindowStateObserver.unregister(); + mMagnificationRegion.setEmpty(); + mRegistered = false; + } + mUnregisterPending = false; } /** @@ -137,24 +171,22 @@ class MagnificationController { } /** - * Sets the magnified and available regions. + * Update our copy of the current magnification region * * @param magnified the magnified region - * @param available the region available for magnification * @param updateSpec {@code true} to update the scale and center based on * the region bounds, {@code false} to leave them as-is */ - private void setMagnifiedRegion(Region magnified, Region available, boolean updateSpec) { + private void onMagnificationRegionChanged(Region magnified, boolean updateSpec) { synchronized (mLock) { boolean magnificationChanged = false; boolean boundsChanged = false; - if (!mMagnifiedRegion.equals(magnified)) { - mMagnifiedRegion.set(magnified); - mMagnifiedRegion.getBounds(mMagnifiedBounds); + if (!mMagnificationRegion.equals(magnified)) { + mMagnificationRegion.set(magnified); + mMagnificationRegion.getBounds(mMagnificationBounds); boundsChanged = true; } - mAvailableRegion.set(available); if (updateSpec) { final MagnificationSpec sentSpec = mSpecAnimationBridge.mSentMagnificationSpec; final float scale = sentSpec.scale; @@ -162,12 +194,12 @@ class MagnificationController { final float offsetY = sentSpec.offsetY; // Compute the new center and update spec as needed. - final float centerX = (mMagnifiedBounds.width() / 2.0f - + mMagnifiedBounds.left - offsetX) / scale; - final float centerY = (mMagnifiedBounds.height() / 2.0f - + mMagnifiedBounds.top - offsetY) / scale; + final float centerX = (mMagnificationBounds.width() / 2.0f + + mMagnificationBounds.left - offsetX) / scale; + final float centerY = (mMagnificationBounds.height() / 2.0f + + mMagnificationBounds.top - offsetY) / scale; magnificationChanged = setScaleAndCenterLocked( - scale, centerX, centerY, false); + scale, centerX, centerY, false, INVALID_ID); } // If magnification changed we already notified for the change. @@ -178,7 +210,7 @@ class MagnificationController { } /** - * Returns whether the magnified region contains the specified + * Returns whether the magnification region contains the specified * screen-relative coordinates. * * @param x the screen-relative X coordinate to check @@ -186,51 +218,36 @@ class MagnificationController { * @return {@code true} if the coordinate is contained within the * magnified region, or {@code false} otherwise */ - public boolean magnifiedRegionContains(float x, float y) { + public boolean magnificationRegionContains(float x, float y) { synchronized (mLock) { - return mMagnifiedRegion.contains((int) x, (int) y); - } - } - - /** - * Returns whether the region available for magnification contains the - * specified screen-relative coordinates. - * - * @param x the screen-relative X coordinate to check - * @param y the screen-relative Y coordinate to check - * @return {@code true} if the coordinate is contained within the - * region available for magnification, or {@code false} otherwise - */ - private boolean availableRegionContains(float x, float y) { - synchronized (mLock) { - return mAvailableRegion.contains((int) x, (int) y); + return mMagnificationRegion.contains((int) x, (int) y); } } /** * Populates the specified rect with the screen-relative bounds of the - * magnified region. If magnification is not enabled, the returned + * magnification region. If magnification is not enabled, the returned * bounds will be empty. * * @param outBounds rect to populate with the bounds of the magnified * region */ - public void getMagnifiedBounds(@NonNull Rect outBounds) { + public void getMagnificationBounds(@NonNull Rect outBounds) { synchronized (mLock) { - outBounds.set(mMagnifiedBounds); + outBounds.set(mMagnificationBounds); } } /** - * Populates the specified region with the screen-relative magnified + * Populates the specified region with the screen-relative magnification * region. If magnification is not enabled, then the returned region * will be empty. * * @param outRegion the region to populate */ - public void getMagnifiedRegion(@NonNull Region outRegion) { + public void getMagnificationRegion(@NonNull Region outRegion) { synchronized (mLock) { - outRegion.set(mMagnifiedRegion); + outRegion.set(mMagnificationRegion); } } @@ -263,8 +280,8 @@ class MagnificationController { */ public float getCenterX() { synchronized (mLock) { - return (mMagnifiedBounds.width() / 2.0f - + mMagnifiedBounds.left - getOffsetX()) / getScale(); + return (mMagnificationBounds.width() / 2.0f + + mMagnificationBounds.left - getOffsetX()) / getScale(); } } @@ -286,8 +303,8 @@ class MagnificationController { */ public float getCenterY() { synchronized (mLock) { - return (mMagnifiedBounds.height() / 2.0f - + mMagnifiedBounds.top - getOffsetY()) / getScale(); + return (mMagnificationBounds.height() / 2.0f + + mMagnificationBounds.top - getOffsetY()) / getScale(); } } @@ -335,17 +352,25 @@ class MagnificationController { */ public boolean reset(boolean animate) { synchronized (mLock) { - final MagnificationSpec spec = mCurrentMagnificationSpec; - final boolean changed = !spec.isNop(); - if (changed) { - spec.clear(); - onMagnificationChangedLocked(); - } - mSpecAnimationBridge.updateSentSpec(spec, animate); - return changed; + return resetLocked(animate); } } + private boolean resetLocked(boolean animate) { + if (!mRegistered) { + return false; + } + final MagnificationSpec spec = mCurrentMagnificationSpec; + final boolean changed = !spec.isNop(); + if (changed) { + spec.clear(); + onMagnificationChangedLocked(); + } + mIdOfLastServiceToMagnify = INVALID_ID; + mSpecAnimationBridge.updateSentSpec(spec, animate); + return changed; + } + /** * Scales the magnified region around the specified pivot point, * optionally animating the transition. If animation is disabled, the @@ -356,16 +381,20 @@ class MagnificationController { * @param pivotY the screen-relative Y coordinate around which to scale * @param animate {@code true} to animate the transition, {@code false} * to transition immediately + * @param id the ID of the service requesting the change * @return {@code true} if the magnification spec changed, {@code false} if * the spec did not change */ - public boolean setScale(float scale, float pivotX, float pivotY, boolean animate) { + public boolean setScale(float scale, float pivotX, float pivotY, boolean animate, int id) { synchronized (mLock) { + if (!mRegistered) { + return false; + } // Constrain scale immediately for use in the pivot calculations. scale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); final Rect viewport = mTempRect; - mMagnifiedRegion.getBounds(viewport); + mMagnificationRegion.getBounds(viewport); final MagnificationSpec spec = mCurrentMagnificationSpec; final float oldScale = spec.scale; final float oldCenterX = (viewport.width() / 2.0f - spec.offsetX) / oldScale; @@ -376,7 +405,8 @@ class MagnificationController { final float offsetY = (oldCenterY - normPivotY) * (oldScale / scale); final float centerX = normPivotX + offsetX; final float centerY = normPivotY + offsetY; - return setScaleAndCenterLocked(scale, centerX, centerY, animate); + mIdOfLastServiceToMagnify = id; + return setScaleAndCenterLocked(scale, centerX, centerY, animate, id); } } @@ -390,12 +420,16 @@ class MagnificationController { * center * @param animate {@code true} to animate the transition, {@code false} * to transition immediately + * @param id the ID of the service requesting the change * @return {@code true} if the magnification spec changed, {@code false} if * the spec did not change */ - public boolean setCenter(float centerX, float centerY, boolean animate) { + public boolean setCenter(float centerX, float centerY, boolean animate, int id) { synchronized (mLock) { - return setScaleAndCenterLocked(Float.NaN, centerX, centerY, animate); + if (!mRegistered) { + return false; + } + return setScaleAndCenterLocked(Float.NaN, centerX, centerY, animate, id); } } @@ -411,19 +445,27 @@ class MagnificationController { * center and scale, or {@link Float#NaN} to leave unchanged * @param animate {@code true} to animate the transition, {@code false} * to transition immediately + * @param id the ID of the service requesting the change * @return {@code true} if the magnification spec changed, {@code false} if * the spec did not change */ - public boolean setScaleAndCenter(float scale, float centerX, float centerY, boolean animate) { + public boolean setScaleAndCenter( + float scale, float centerX, float centerY, boolean animate, int id) { synchronized (mLock) { - return setScaleAndCenterLocked(scale, centerX, centerY, animate); + if (!mRegistered) { + return false; + } + return setScaleAndCenterLocked(scale, centerX, centerY, animate, id); } } private boolean setScaleAndCenterLocked(float scale, float centerX, float centerY, - boolean animate) { + boolean animate, int id) { final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY); mSpecAnimationBridge.updateSentSpec(mCurrentMagnificationSpec, animate); + if (isMagnifying() && (id != INVALID_ID)) { + mIdOfLastServiceToMagnify = id; + } return changed; } @@ -432,22 +474,42 @@ class MagnificationController { * * @param offsetX the amount in pixels to offset the X center * @param offsetY the amount in pixels to offset the Y center + * @param id the ID of the service requesting the change */ - public void offsetMagnifiedRegionCenter(float offsetX, float offsetY) { + public void offsetMagnifiedRegionCenter(float offsetX, float offsetY, int id) { synchronized (mLock) { + if (!mRegistered) { + return; + } + final MagnificationSpec currSpec = mCurrentMagnificationSpec; final float nonNormOffsetX = currSpec.offsetX - offsetX; currSpec.offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0); final float nonNormOffsetY = currSpec.offsetY - offsetY; currSpec.offsetY = MathUtils.constrain(nonNormOffsetY, getMinOffsetYLocked(), 0); + if (id != INVALID_ID) { + mIdOfLastServiceToMagnify = id; + } mSpecAnimationBridge.updateSentSpec(currSpec, false); } } + /** + * Get the ID of the last service that changed the magnification spec. + * + * @return The id + */ + public int getIdOfLastServiceToMagnify() { + return mIdOfLastServiceToMagnify; + } + private void onMagnificationChangedLocked() { mAms.onMagnificationStateChanged(); - mAms.notifyMagnificationChanged(mMagnifiedRegion, + mAms.notifyMagnificationChanged(mMagnificationRegion, getScale(), getCenterX(), getCenterY()); + if (mUnregisterPending && !isMagnifying()) { + unregisterInternalLocked(); + } } /** @@ -503,8 +565,8 @@ class MagnificationController { scale = getScale(); } - // Ensure requested center is within the available region. - if (!availableRegionContains(centerX, centerY)) { + // Ensure requested center is within the magnification region. + if (!magnificationRegionContains(centerX, centerY)) { return false; } @@ -518,16 +580,16 @@ class MagnificationController { changed = true; } - final float nonNormOffsetX = mMagnifiedBounds.width() / 2.0f - + mMagnifiedBounds.left - centerX * scale; + final float nonNormOffsetX = mMagnificationBounds.width() / 2.0f + + mMagnificationBounds.left - centerX * scale; final float offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0); if (Float.compare(currSpec.offsetX, offsetX) != 0) { currSpec.offsetX = offsetX; changed = true; } - final float nonNormOffsetY = mMagnifiedBounds.height() / 2.0f - + mMagnifiedBounds.top - centerY * scale; + final float nonNormOffsetY = mMagnificationBounds.height() / 2.0f + + mMagnificationBounds.top - centerY * scale; final float offsetY = MathUtils.constrain(nonNormOffsetY, getMinOffsetYLocked(), 0); if (Float.compare(currSpec.offsetY, offsetY) != 0) { currSpec.offsetY = offsetY; @@ -542,12 +604,12 @@ class MagnificationController { } private float getMinOffsetXLocked() { - final float viewportWidth = mMagnifiedBounds.width(); + final float viewportWidth = mMagnificationBounds.width(); return viewportWidth - viewportWidth * mCurrentMagnificationSpec.scale; } private float getMinOffsetYLocked() { - final float viewportHeight = mMagnifiedBounds.height(); + final float viewportHeight = mMagnificationBounds.height(); return viewportHeight - viewportHeight * mCurrentMagnificationSpec.scale; } @@ -595,7 +657,7 @@ class MagnificationController { final float scale = getSentScale(); final float offsetX = getSentOffsetX(); final float offsetY = getSentOffsetY(); - getMagnifiedBounds(outFrame); + getMagnificationBounds(outFrame); outFrame.offset((int) -offsetX, (int) -offsetY); outFrame.scale(1.0f / scale); } @@ -603,7 +665,7 @@ class MagnificationController { private void requestRectangleOnScreen(int left, int top, int right, int bottom) { synchronized (mLock) { final Rect magnifiedFrame = mTempRect; - getMagnifiedBounds(magnifiedFrame); + getMagnificationBounds(magnifiedFrame); if (!magnifiedFrame.intersects(left, top, right, bottom)) { return; } @@ -640,7 +702,7 @@ class MagnificationController { } final float scale = getScale(); - offsetMagnifiedRegionCenter(scrollX * scale, scrollY * scale); + offsetMagnifiedRegionCenter(scrollX * scale, scrollY * scale, INVALID_ID); } } @@ -656,7 +718,7 @@ class MagnificationController { /** * The magnification spec that was sent to the window manager. This should - * only be accessed and modified on the main (e.g. animation) thread. + * only be accessed with the lock held. */ private final MagnificationSpec mSentMagnificationSpec = MagnificationSpec.obtain(); @@ -667,8 +729,13 @@ class MagnificationController { private final ValueAnimator mTransformationAnimator; private final long mMainThreadId; + private final Object mLock; - private SpecAnimationBridge(Context context) { + @GuardedBy("mLock") + private boolean mEnabled = false; + + private SpecAnimationBridge(Context context, Object lock) { + mLock = lock; final Looper mainLooper = context.getMainLooper(); mMainThreadId = mainLooper.getThread().getId(); @@ -685,9 +752,19 @@ class MagnificationController { mTransformationAnimator.setInterpolator(new DecelerateInterpolator(2.5f)); } - public void cancel() { - if (mTransformationAnimator != null && mTransformationAnimator.isRunning()) { - mTransformationAnimator.cancel(); + /** + * Enabled means the bridge will accept input. When not enabled, the output of the animator + * will be ignored + */ + public void setEnabled(boolean enabled) { + synchronized (mLock) { + if (enabled != mEnabled) { + mEnabled = enabled; + if (!mEnabled) { + mSentMagnificationSpec.clear(); + mWindowManager.setMagnificationSpec(mSentMagnificationSpec); + } + } } } @@ -710,28 +787,32 @@ class MagnificationController { } // If the current and sent specs don't match, update the sent spec. - final boolean changed = !mSentMagnificationSpec.equals(spec); - if (changed) { - if (animate) { - animateMagnificationSpec(spec); - } else { - setMagnificationSpec(spec); + synchronized (mLock) { + final boolean changed = !mSentMagnificationSpec.equals(spec); + if (changed) { + if (animate) { + animateMagnificationSpecLocked(spec); + } else { + setMagnificationSpecLocked(spec); + } } } } - private void animateMagnificationSpec(MagnificationSpec toSpec) { + private void animateMagnificationSpecLocked(MagnificationSpec toSpec) { mTransformationAnimator.setObjectValues(mSentMagnificationSpec, toSpec); mTransformationAnimator.start(); } - private void setMagnificationSpec(MagnificationSpec spec) { - if (DEBUG_SET_MAGNIFICATION_SPEC) { - Slog.i(LOG_TAG, "Sending: " + spec); - } + private void setMagnificationSpecLocked(MagnificationSpec spec) { + if (mEnabled) { + if (DEBUG_SET_MAGNIFICATION_SPEC) { + Slog.i(LOG_TAG, "Sending: " + spec); + } - mSentMagnificationSpec.setTo(spec); - mWindowManager.setMagnificationSpec(spec); + mSentMagnificationSpec.setTo(spec); + mWindowManager.setMagnificationSpec(spec); + } } private class UpdateHandler extends Handler { @@ -759,12 +840,16 @@ class MagnificationController { @Override public MagnificationSpec get(SpecAnimationBridge object) { - return object.mSentMagnificationSpec; + synchronized (object.mLock) { + return object.mSentMagnificationSpec; + } } @Override public void set(SpecAnimationBridge object, MagnificationSpec value) { - object.setMagnificationSpec(value); + synchronized (object.mLock) { + object.setMagnificationSpecLocked(value); + } } } @@ -862,15 +947,14 @@ class MagnificationController { } @Override - public void onMagnifiedBoundsChanged(Region magnified, Region available) { + public void onMagnificationRegionChanged(Region magnificationRegion) { final SomeArgs args = SomeArgs.obtain(); - args.arg1 = Region.obtain(magnified); - args.arg2 = Region.obtain(available); + args.arg1 = Region.obtain(magnificationRegion); mHandler.obtainMessage(MESSAGE_ON_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget(); } - private void handleOnMagnifiedBoundsChanged(Region magnified, Region available) { - mController.setMagnifiedRegion(magnified, available, mSpecIsDirty); + private void handleOnMagnifiedBoundsChanged(Region magnificationRegion) { + mController.onMagnificationRegionChanged(magnificationRegion, mSpecIsDirty); mSpecIsDirty = false; } @@ -911,8 +995,15 @@ class MagnificationController { mController.resetIfNeeded(true); } - public void getRegions(@NonNull Region outMagnified, @NonNull Region outAvailable) { - mWindowManager.getMagnificationRegions(outMagnified, outAvailable); + /** + * This method is used to get the magnification region in the tiny time slice between + * registering the callbacks and handling the message. + * TODO: Elimiante this extra path, perhaps by processing the message immediately + * + * @param outMagnificationRegion + */ + public void getMagnificationRegion(@NonNull Region outMagnificationRegion) { + mWindowManager.getMagnificationRegion(outMagnificationRegion); } private class CallbackHandler extends Handler { @@ -926,10 +1017,8 @@ class MagnificationController { case MESSAGE_ON_MAGNIFIED_BOUNDS_CHANGED: { final SomeArgs args = (SomeArgs) message.obj; final Region magnifiedBounds = (Region) args.arg1; - final Region availableBounds = (Region) args.arg2; - handleOnMagnifiedBoundsChanged(magnifiedBounds, availableBounds); + handleOnMagnifiedBoundsChanged(magnifiedBounds); magnifiedBounds.recycle(); - availableBounds.recycle(); } break; case MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED: { final SomeArgs args = (SomeArgs) message.obj; diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java index 818ac814eb4e3..39bc8098f6a55 100644 --- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java @@ -237,7 +237,7 @@ class MagnificationGestureHandler implements EventStreamTransformation { final float eventX = event.getX(); final float eventY = event.getY(); if (mMagnificationController.isMagnifying() - && mMagnificationController.magnifiedRegionContains(eventX, eventY)) { + && mMagnificationController.magnificationRegionContains(eventX, eventY)) { final float scale = mMagnificationController.getScale(); final float scaledOffsetX = mMagnificationController.getOffsetX(); final float scaledOffsetY = mMagnificationController.getOffsetY(); @@ -381,7 +381,8 @@ class MagnificationGestureHandler implements EventStreamTransformation { Slog.i(LOG_TAG, "Panned content by scrollX: " + distanceX + " scrollY: " + distanceY); } - mMagnificationController.offsetMagnifiedRegionCenter(distanceX, distanceY); + mMagnificationController.offsetMagnifiedRegionCenter(distanceX, distanceY, + AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); return true; } @@ -421,7 +422,8 @@ class MagnificationGestureHandler implements EventStreamTransformation { final float pivotX = detector.getFocusX(); final float pivotY = detector.getFocusY(); - mMagnificationController.setScale(scale, pivotX, pivotY, false); + mMagnificationController.setScale(scale, pivotX, pivotY, false, + AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); return true; } @@ -469,14 +471,14 @@ class MagnificationGestureHandler implements EventStreamTransformation { } final float eventX = event.getX(); final float eventY = event.getY(); - if (mMagnificationController.magnifiedRegionContains(eventX, eventY)) { + if (mMagnificationController.magnificationRegionContains(eventX, eventY)) { if (mLastMoveOutsideMagnifiedRegion) { mLastMoveOutsideMagnifiedRegion = false; - mMagnificationController.setCenter(eventX, - eventY, true); + mMagnificationController.setCenter(eventX, eventY, true, + AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); } else { - mMagnificationController.setCenter(eventX, - eventY, false); + mMagnificationController.setCenter(eventX, eventY, false, + AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); } } else { mLastMoveOutsideMagnifiedRegion = true; @@ -571,7 +573,7 @@ class MagnificationGestureHandler implements EventStreamTransformation { switch (action) { case MotionEvent.ACTION_DOWN: { mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE); - if (!mMagnificationController.magnifiedRegionContains( + if (!mMagnificationController.magnificationRegionContains( event.getX(), event.getY())) { transitionToDelegatingStateAndClear(); return; @@ -616,7 +618,7 @@ class MagnificationGestureHandler implements EventStreamTransformation { return; } mHandler.removeMessages(MESSAGE_ON_ACTION_TAP_AND_HOLD); - if (!mMagnificationController.magnifiedRegionContains( + if (!mMagnificationController.magnificationRegionContains( event.getX(), event.getY())) { transitionToDelegatingStateAndClear(); return; @@ -726,7 +728,8 @@ class MagnificationGestureHandler implements EventStreamTransformation { if (!mMagnificationController.isMagnifying()) { final float targetScale = mMagnificationController.getPersistedScale(); final float scale = MathUtils.constrain(targetScale, MIN_SCALE, MAX_SCALE); - mMagnificationController.setScaleAndCenter(scale, up.getX(), up.getY(), true); + mMagnificationController.setScaleAndCenter(scale, up.getX(), up.getY(), true, + AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); } else { mMagnificationController.reset(true); } @@ -742,7 +745,8 @@ class MagnificationGestureHandler implements EventStreamTransformation { final float targetScale = mMagnificationController.getPersistedScale(); final float scale = MathUtils.constrain(targetScale, MIN_SCALE, MAX_SCALE); - mMagnificationController.setScaleAndCenter(scale, down.getX(), down.getY(), true); + mMagnificationController.setScaleAndCenter(scale, down.getX(), down.getY(), true, + AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); transitionToState(STATE_VIEWPORT_DRAGGING); } diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 3ef077b74b621..101f56f49241f 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -124,9 +124,9 @@ final class AccessibilityController { } } - public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) { + public void getMagnificationRegionLocked(Region outMagnificationRegion) { if (mDisplayMagnifier != null) { - mDisplayMagnifier.getMagnificationRegionsLocked(outMagnified, outAvailable); + mDisplayMagnifier.getMagnificationRegionLocked(outMagnificationRegion); } } @@ -400,8 +400,8 @@ final class AccessibilityController { return spec; } - public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) { - mMagnifedViewport.getBoundsLocked(outMagnified, outAvailable); + public void getMagnificationRegionLocked(Region outMagnificationRegion) { + mMagnifedViewport.getMagnificationRegionLocked(outMagnificationRegion); } public void destroyLocked() { @@ -424,10 +424,8 @@ final class AccessibilityController { private final Matrix mTempMatrix = new Matrix(); - private final Region mMagnifiedBounds = new Region(); - private final Region mAvailableBounds = new Region(); - private final Region mOldMagnifiedBounds = new Region(); - private final Region mOldAvailableBounds = new Region(); + private final Region mMagnificationRegion = new Region(); + private final Region mOldMagnificationRegion = new Region(); private final Path mCircularPath; @@ -463,10 +461,8 @@ final class AccessibilityController { recomputeBoundsLocked(); } - public void getBoundsLocked(@NonNull Region outMagnified, - @NonNull Region outAvailable) { - outMagnified.set(mMagnifiedBounds); - outAvailable.set(mAvailableBounds); + public void getMagnificationRegionLocked(@NonNull Region outMagnificationRegion) { + outMagnificationRegion.set(mMagnificationRegion); } public void updateMagnificationSpecLocked(MagnificationSpec spec) { @@ -488,11 +484,12 @@ final class AccessibilityController { final int screenWidth = mTempPoint.x; final int screenHeight = mTempPoint.y; - mMagnifiedBounds.set(0, 0, 0, 0); - mAvailableBounds.set(0, 0, screenWidth, screenHeight); + mMagnificationRegion.set(0, 0, 0, 0); + final Region availableBounds = mTempRegion1; + availableBounds.set(0, 0, screenWidth, screenHeight); if (mCircularPath != null) { - mAvailableBounds.setPath(mCircularPath, mAvailableBounds); + availableBounds.setPath(mCircularPath, availableBounds); } Region nonMagnifiedBounds = mTempRegion4; @@ -526,21 +523,21 @@ final class AccessibilityController { (int) windowFrame.right, (int) windowFrame.bottom); // Only update new regions Region portionOfWindowAlreadyAccountedFor = mTempRegion3; - portionOfWindowAlreadyAccountedFor.set(mMagnifiedBounds); + portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion); portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION); windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE); if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) { - mMagnifiedBounds.op(windowBounds, Region.Op.UNION); - mMagnifiedBounds.op(mAvailableBounds, Region.Op.INTERSECT); + mMagnificationRegion.op(windowBounds, Region.Op.UNION); + mMagnificationRegion.op(availableBounds, Region.Op.INTERSECT); } else { nonMagnifiedBounds.op(windowBounds, Region.Op.UNION); - mAvailableBounds.op(windowBounds, Region.Op.DIFFERENCE); + availableBounds.op(windowBounds, Region.Op.DIFFERENCE); } // Update accounted bounds Region accountedBounds = mTempRegion2; - accountedBounds.set(mMagnifiedBounds); + accountedBounds.set(mMagnificationRegion); accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION); accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT); @@ -556,43 +553,36 @@ final class AccessibilityController { visibleWindows.clear(); - mMagnifiedBounds.op(mDrawBorderInset, mDrawBorderInset, + mMagnificationRegion.op(mDrawBorderInset, mDrawBorderInset, screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset, Region.Op.INTERSECT); - final boolean magnifiedChanged = !mOldMagnifiedBounds.equals(mMagnifiedBounds); - final boolean availableChanged = !mOldAvailableBounds.equals(mAvailableBounds); - if (magnifiedChanged || availableChanged) { - if (magnifiedChanged) { - mWindow.setBounds(mMagnifiedBounds); - Rect dirtyRect = mTempRect1; - if (mFullRedrawNeeded) { - mFullRedrawNeeded = false; - dirtyRect.set(mDrawBorderInset, mDrawBorderInset, - screenWidth - mDrawBorderInset, - screenHeight - mDrawBorderInset); - mWindow.invalidate(dirtyRect); - } else { - Region dirtyRegion = mTempRegion3; - dirtyRegion.set(mMagnifiedBounds); - dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION); - dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT); - dirtyRegion.getBounds(dirtyRect); - mWindow.invalidate(dirtyRect); - } - - mOldMagnifiedBounds.set(mMagnifiedBounds); - } - - if (availableChanged) { - mOldAvailableBounds.set(mAvailableBounds); + final boolean magnifiedChanged = + !mOldMagnificationRegion.equals(mMagnificationRegion); + if (magnifiedChanged) { + mWindow.setBounds(mMagnificationRegion); + final Rect dirtyRect = mTempRect1; + if (mFullRedrawNeeded) { + mFullRedrawNeeded = false; + dirtyRect.set(mDrawBorderInset, mDrawBorderInset, + screenWidth - mDrawBorderInset, + screenHeight - mDrawBorderInset); + mWindow.invalidate(dirtyRect); + } else { + final Region dirtyRegion = mTempRegion3; + dirtyRegion.set(mMagnificationRegion); + dirtyRegion.op(mOldMagnificationRegion, Region.Op.UNION); + dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT); + dirtyRegion.getBounds(dirtyRect); + mWindow.invalidate(dirtyRect); } + mOldMagnificationRegion.set(mMagnificationRegion); final SomeArgs args = SomeArgs.obtain(); - args.arg1 = Region.obtain(mMagnifiedBounds); - args.arg2 = Region.obtain(mAvailableBounds); + args.arg1 = Region.obtain(mMagnificationRegion); mHandler.obtainMessage( - MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget(); + MyHandler.MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED, args) + .sendToTarget(); } } @@ -616,14 +606,14 @@ final class AccessibilityController { public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) { if (shown) { mFullRedrawNeeded = true; - mOldMagnifiedBounds.set(0, 0, 0, 0); + mOldMagnificationRegion.set(0, 0, 0, 0); } mWindow.setShown(shown, animate); } public void getMagnifiedFrameInContentCoordsLocked(Rect rect) { MagnificationSpec spec = mMagnificationSpec; - mMagnifiedBounds.getBounds(rect); + mMagnificationRegion.getBounds(rect); rect.offset((int) -spec.offsetX, (int) -spec.offsetY); rect.scale(1.0f / spec.scale); } @@ -886,7 +876,7 @@ final class AccessibilityController { } private class MyHandler extends Handler { - public static final int MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED = 1; + public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1; public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2; public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3; public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4; @@ -899,13 +889,11 @@ final class AccessibilityController { @Override public void handleMessage(Message message) { switch (message.what) { - case MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED: { + case MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED: { final SomeArgs args = (SomeArgs) message.obj; final Region magnifiedBounds = (Region) args.arg1; - final Region availableBounds = (Region) args.arg2; - mCallbacks.onMagnifiedBoundsChanged(magnifiedBounds, availableBounds); + mCallbacks.onMagnificationRegionChanged(magnifiedBounds); magnifiedBounds.recycle(); - availableBounds.recycle(); } break; case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index cf415ff4e6474..0c91307e88e14 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -10975,12 +10975,10 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void getMagnificationRegions(@NonNull Region outMagnified, - @NonNull Region outAvailable) { + public void getMagnificationRegion(@NonNull Region magnificationRegion) { synchronized (mWindowMap) { if (mAccessibilityController != null) { - mAccessibilityController.getMagnificationRegionsLocked( - outMagnified, outAvailable); + mAccessibilityController.getMagnificationRegionLocked(magnificationRegion); } else { throw new IllegalStateException("Magnification callbacks not set!"); }