diff --git a/core/api/current.txt b/core/api/current.txt index ea552665c71de..676c4b4357085 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -3254,6 +3254,28 @@ package android.accessibilityservice { method public boolean willContinue(); } + public final class MagnificationConfig implements android.os.Parcelable { + method public int describeContents(); + method public float getCenterX(); + method public float getCenterY(); + method public int getMode(); + method public float getScale(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int DEFAULT_MODE = 0; // 0x0 + field public static final int FULLSCREEN_MODE = 1; // 0x1 + field public static final int WINDOW_MODE = 2; // 0x2 + } + + public static final class MagnificationConfig.Builder { + ctor public MagnificationConfig.Builder(); + method @NonNull public android.accessibilityservice.MagnificationConfig build(); + method @NonNull public android.accessibilityservice.MagnificationConfig.Builder setCenterX(float); + method @NonNull public android.accessibilityservice.MagnificationConfig.Builder setCenterY(float); + method @NonNull public android.accessibilityservice.MagnificationConfig.Builder setMode(int); + method @NonNull public android.accessibilityservice.MagnificationConfig.Builder setScale(float); + } + public final class TouchInteractionController { method public int getDisplayId(); method public int getMaxPointerCount(); diff --git a/core/java/android/accessibilityservice/MagnificationConfig.aidl b/core/java/android/accessibilityservice/MagnificationConfig.aidl new file mode 100644 index 0000000000000..fe415a864b801 --- /dev/null +++ b/core/java/android/accessibilityservice/MagnificationConfig.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.accessibilityservice; + +parcelable MagnificationConfig; diff --git a/core/java/android/accessibilityservice/MagnificationConfig.java b/core/java/android/accessibilityservice/MagnificationConfig.java new file mode 100644 index 0000000000000..8884508bb2b04 --- /dev/null +++ b/core/java/android/accessibilityservice/MagnificationConfig.java @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.accessibilityservice; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * This class describes the magnification config for {@link AccessibilityService} to control the + * magnification. + * + *

+ * When the magnification config uses {@link #DEFAULT_MODE}, + * {@link AccessibilityService} will be able to control the activated magnifier on the display. + * If there is no magnifier activated, it controls the last-activated magnification mode. + * If there is no magnifier activated before, it controls full-screen magnifier by default. + *

+ * + *

+ * When the magnification config uses {@link #FULLSCREEN_MODE}. {@link AccessibilityService} will + * be able to control full-screen magnifier on the display. + *

+ * + *

+ * When the magnification config uses {@link #WINDOW_MODE}. {@link AccessibilityService} will be + * able to control the activated window magnifier on the display. + *

+ * + *

+ * If the other magnification configs, scale centerX and centerY, are not set by the + * {@link Builder}, the configs should be current values or default values. And the center + * position ordinarily is the center of the screen. + *

+ */ +public final class MagnificationConfig implements Parcelable { + + /** The controlling magnification mode. It controls the activated magnifier. */ + public static final int DEFAULT_MODE = 0; + /** The controlling magnification mode. It controls fullscreen magnifier. */ + public static final int FULLSCREEN_MODE = 1; + /** The controlling magnification mode. It controls window magnifier. */ + public static final int WINDOW_MODE = 2; + + @IntDef(prefix = {"MAGNIFICATION_MODE"}, value = { + DEFAULT_MODE, + FULLSCREEN_MODE, + WINDOW_MODE, + }) + @Retention(RetentionPolicy.SOURCE) + @interface MAGNIFICATION_MODE { + } + + private int mMode = DEFAULT_MODE; + private float mScale = Float.NaN; + private float mCenterX = Float.NaN; + private float mCenterY = Float.NaN; + + private MagnificationConfig() { + /* do nothing */ + } + + private MagnificationConfig(@NonNull Parcel parcel) { + mMode = parcel.readInt(); + mScale = parcel.readFloat(); + mCenterX = parcel.readFloat(); + mCenterY = parcel.readFloat(); + } + + /** + * Returns the magnification mode that is the current activated mode or the controlling mode of + * the config. + * + * @return The magnification mode + */ + public int getMode() { + return mMode; + } + + /** + * Returns the magnification scale of the controlling magnifier + * + * @return the scale If the controlling magnifier is not activated, it returns 1 by default + */ + public float getScale() { + return mScale; + } + + /** + * Returns the screen-relative X coordinate of the center of the magnification viewport. + * + * @return the X coordinate. If the controlling magnifier is {@link #WINDOW_MODE} but not + * enabled, it returns {@link Float#NaN}. If the controlling magnifier is {@link + * #FULLSCREEN_MODE} but not enabled, it returns 0 + */ + public float getCenterX() { + return mCenterX; + } + + /** + * Returns the screen-relative Y coordinate of the center of the magnification viewport. + * + * @return the Y coordinate If the controlling magnifier is {@link #WINDOW_MODE} but not + * enabled, it returns {@link Float#NaN}. If the controlling magnifier is {@link + * #FULLSCREEN_MODE} but not enabled, it returns 0 + */ + public float getCenterY() { + return mCenterY; + } + + @NonNull + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder("MagnificationConfig["); + stringBuilder.append("mode: ").append(getMode()); + stringBuilder.append(", "); + stringBuilder.append("scale: ").append(getScale()); + stringBuilder.append(", "); + stringBuilder.append("centerX: ").append(getCenterX()); + stringBuilder.append(", "); + stringBuilder.append("centerY: ").append(getCenterY()); + stringBuilder.append("] "); + return stringBuilder.toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mMode); + parcel.writeFloat(mScale); + parcel.writeFloat(mCenterX); + parcel.writeFloat(mCenterY); + } + + /** + * Builder for creating {@link MagnificationConfig} objects. + */ + public static final class Builder { + + private int mMode = DEFAULT_MODE; + private float mScale = Float.NaN; + private float mCenterX = Float.NaN; + private float mCenterY = Float.NaN; + + /** + * Creates a new Builder. + */ + public Builder() { + } + + /** + * Sets the magnification mode. + * + * @param mode The magnification mode + * @return This builder + */ + @NonNull + public MagnificationConfig.Builder setMode(@MAGNIFICATION_MODE int mode) { + mMode = mode; + return this; + } + + /** + * Sets the magnification scale. + * + * @param scale The magnification scale + * @return This builder + */ + @NonNull + public MagnificationConfig.Builder setScale(float scale) { + mScale = scale; + return this; + } + + /** + * Sets the X coordinate of the center of the magnification viewport. + * + * @param centerX the screen-relative X coordinate around which to + * center and scale, or {@link Float#NaN} to leave unchanged + * @return This builder + */ + @NonNull + public MagnificationConfig.Builder setCenterX(float centerX) { + mCenterX = centerX; + return this; + } + + /** + * Sets the Y coordinate of the center of the magnification viewport. + * + * @param centerY the screen-relative Y coordinate around which to + * center and scale, or {@link Float#NaN} to leave unchanged + * @return This builder + */ + @NonNull + public MagnificationConfig.Builder setCenterY(float centerY) { + mCenterY = centerY; + return this; + } + + /** + * Builds and returns a {@link MagnificationConfig} + */ + @NonNull + public MagnificationConfig build() { + MagnificationConfig magnificationConfig = new MagnificationConfig(); + magnificationConfig.mMode = mMode; + magnificationConfig.mScale = mScale; + magnificationConfig.mCenterX = mCenterX; + magnificationConfig.mCenterY = mCenterY; + return magnificationConfig; + } + } + + /** + * @see Parcelable.Creator + */ + public static final @NonNull Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public MagnificationConfig createFromParcel(Parcel parcel) { + return new MagnificationConfig(parcel); + } + + public MagnificationConfig[] newArray(int size) { + return new MagnificationConfig[size]; + } + }; +} diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 67bb7262b6723..f1599e4d7ffa1 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -39,6 +39,7 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.AccessibilityTrace; import android.accessibilityservice.IAccessibilityServiceClient; import android.accessibilityservice.IAccessibilityServiceConnection; +import android.accessibilityservice.MagnificationConfig; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; @@ -1101,8 +1102,12 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ try { MagnificationProcessor magnificationProcessor = mSystemSupport.getMagnificationProcessor(); - return magnificationProcessor - .setScaleAndCenter(displayId, scale, centerX, centerY, animate, mId); + final MagnificationConfig config = new MagnificationConfig.Builder() + .setScale(scale) + .setCenterX(centerX) + .setCenterY(centerY).build(); + return magnificationProcessor.setMagnificationConfig(displayId, config, animate, + mId); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java index 6473bf5ffc3ef..327f087535248 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java @@ -84,6 +84,8 @@ public class MagnificationController implements WindowMagnificationManager.Callb @GuardedBy("mLock") private int mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE; + @GuardedBy("mLock") + private int mLastActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; // Track the active user to reset the magnification and get the associated user settings. private @UserIdInt int mUserId = UserHandle.USER_SYSTEM; @GuardedBy("mLock") @@ -239,6 +241,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb synchronized (mLock) { mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW; + mLastActivatedMode = mActivatedMode; } logMagnificationModeWithImeOnIfNeeded(); disableFullScreenMagnificationIfNeeded(displayId); @@ -276,6 +279,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb synchronized (mLock) { mActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; + mLastActivatedMode = mActivatedMode; } logMagnificationModeWithImeOnIfNeeded(); } else { @@ -297,6 +301,16 @@ public class MagnificationController implements WindowMagnificationManager.Callb logMagnificationModeWithImeOnIfNeeded(); } + /** + * Returns the last activated magnification mode. If there is no activated magnifier before, it + * returns fullscreen mode by default. + */ + public int getLastActivatedMode() { + synchronized (mLock) { + return mLastActivatedMode; + } + } + /** * Wrapper method of logging the magnification activated mode and its duration of the usage * when the magnification is disabled. @@ -336,6 +350,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb synchronized (mLock) { fullMagnificationController = mFullScreenMagnificationController; windowMagnificationManager = mWindowMagnificationMgr; + mLastActivatedMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; } mScaleProvider.onUserChanged(userId); @@ -462,7 +477,15 @@ public class MagnificationController implements WindowMagnificationManager.Callb return mTempPoint; } - private boolean isActivated(int displayId, int mode) { + /** + * Return {@code true} if the specified magnification mode on the given display is activated + * or not. + * + * @param displayId The logical displayId. + * @param mode It's either ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN or + * ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW. + */ + public boolean isActivated(int displayId, int mode) { boolean isActivated = false; if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) { synchronized (mLock) { 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 efc6d515fdb83..2324a5a781f41 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java @@ -16,6 +16,13 @@ package com.android.server.accessibility.magnification; +import static android.accessibilityservice.MagnificationConfig.DEFAULT_MODE; +import static android.accessibilityservice.MagnificationConfig.FULLSCREEN_MODE; +import static android.accessibilityservice.MagnificationConfig.WINDOW_MODE; +import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; +import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW; + +import android.accessibilityservice.MagnificationConfig; import android.annotation.NonNull; import android.graphics.Region; @@ -23,6 +30,22 @@ import android.graphics.Region; * Processor class for AccessibilityService connection to control magnification on the specified * display. This wraps the function of magnification controller. * + *

+ * If the magnification config uses {@link DEFAULT_MODE}. This processor will control the current + * activated magnifier on the display. If there is no magnifier activated, it controls + * full-screen magnifier by default. + *

+ * + *

+ * If the magnification config uses {@link FULLSCREEN_MODE}. This processor will control + * full-screen magnifier on the display. + *

+ * + *

+ * If the magnification config uses {@link WINDOW_MODE}. This processor will control + * the activated window magnifier on the display. + *

+ * * @see MagnificationController * @see FullScreenMagnificationController */ @@ -35,53 +58,166 @@ public class MagnificationProcessor { } /** - * {@link FullScreenMagnificationController#getScale(int)} + * Gets the magnification config of the display. + * + * @param displayId The logical display id + * @return the magnification config + */ + public @NonNull MagnificationConfig getMagnificationConfig(int displayId) { + final int mode = getControllingMode(displayId); + MagnificationConfig.Builder builder = new MagnificationConfig.Builder(); + if (mode == FULLSCREEN_MODE) { + final FullScreenMagnificationController fullScreenMagnificationController = + mController.getFullScreenMagnificationController(); + builder.setMode(mode) + .setScale(fullScreenMagnificationController.getScale(displayId)) + .setCenterX(fullScreenMagnificationController.getCenterX(displayId)) + .setCenterY(fullScreenMagnificationController.getCenterY(displayId)); + } else if (mode == WINDOW_MODE) { + final WindowMagnificationManager windowMagnificationManager = + mController.getWindowMagnificationMgr(); + builder.setMode(mode) + .setScale(windowMagnificationManager.getScale(displayId)) + .setCenterX(windowMagnificationManager.getCenterX(displayId)) + .setCenterY(windowMagnificationManager.getCenterY(displayId)); + } + return builder.build(); + } + + /** + * Sets the magnification config of the display. If animation is disabled, the transition + * is immediate. + * + * @param displayId The logical display id + * @param config The magnification config + * @param animate {@code true} to animate from the current config or + * {@code false} to set the config 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 setMagnificationConfig(int displayId, @NonNull MagnificationConfig config, + boolean animate, int id) { + int configMode = config.getMode(); + if (configMode == DEFAULT_MODE) { + configMode = getControllingMode(displayId); + } + if (configMode == FULLSCREEN_MODE) { + return setScaleAndCenterForFullScreenMagnification(displayId, config.getScale(), + config.getCenterX(), config.getCenterY(), + animate, id); + } else if (configMode == WINDOW_MODE) { + return mController.getWindowMagnificationMgr().enableWindowMagnification(displayId, + config.getScale(), config.getCenterX(), config.getCenterY()); + } + return false; + } + + /** + * Returns the magnification scale. If an animation is in progress, + * this reflects the end state of the animation. + * + * @param displayId The logical display id. + * @return the scale */ public float getScale(int displayId) { - return mController.getFullScreenMagnificationController().getScale(displayId); + int mode = getControllingMode(displayId); + if (mode == FULLSCREEN_MODE) { + return mController.getFullScreenMagnificationController().getScale(displayId); + } else if (mode == WINDOW_MODE) { + return mController.getWindowMagnificationMgr().getScale(displayId); + } + return 0; } /** - * {@link FullScreenMagnificationController#getCenterX(int)} + * Returns the magnification center in X coordinate of the controlling magnification mode. + * If the service can control magnification but fullscreen magnifier is not registered, it will + * register the magnifier for this call then unregister the magnifier finally to make the + * magnification center correct. + * + * @param displayId The logical display id + * @param canControlMagnification Whether the service can control magnification + * @return the X coordinate */ public float getCenterX(int displayId, boolean canControlMagnification) { - boolean registeredJustForThisCall = registerMagnificationIfNeeded(displayId, - canControlMagnification); - try { - return mController.getFullScreenMagnificationController().getCenterX(displayId); - } finally { - if (registeredJustForThisCall) { - unregister(displayId); + int mode = getControllingMode(displayId); + if (mode == FULLSCREEN_MODE) { + boolean registeredJustForThisCall = registerDisplayMagnificationIfNeeded(displayId, + canControlMagnification); + try { + return mController.getFullScreenMagnificationController().getCenterX(displayId); + } finally { + if (registeredJustForThisCall) { + unregister(displayId); + } } + } else if (mode == WINDOW_MODE) { + return mController.getWindowMagnificationMgr().getCenterX(displayId); } + return 0; } /** - * {@link FullScreenMagnificationController#getCenterY(int)} + * Returns the magnification center in Y coordinate of the controlling magnification mode. + * If the service can control magnification but fullscreen magnifier is not registered, it will + * register the magnifier for this call then unregister the magnifier finally to make the + * magnification center correct. + * + * @param displayId The logical display id + * @param canControlMagnification Whether the service can control magnification + * @return the Y coordinate */ public float getCenterY(int displayId, boolean canControlMagnification) { - boolean registeredJustForThisCall = registerMagnificationIfNeeded(displayId, - canControlMagnification); - try { - return mController.getFullScreenMagnificationController().getCenterY(displayId); - } finally { - if (registeredJustForThisCall) { - unregister(displayId); + int mode = getControllingMode(displayId); + if (mode == FULLSCREEN_MODE) { + boolean registeredJustForThisCall = registerDisplayMagnificationIfNeeded(displayId, + canControlMagnification); + try { + return mController.getFullScreenMagnificationController().getCenterY(displayId); + } finally { + if (registeredJustForThisCall) { + unregister(displayId); + } } + } else if (mode == WINDOW_MODE) { + return mController.getWindowMagnificationMgr().getCenterY(displayId); } + return 0; } /** - * {@link FullScreenMagnificationController#getMagnificationRegion(int, Region)} + * Return the magnification bounds of the current controlling magnification on the given + * display. If the magnifier is not enabled, it returns an empty region. + * If the service can control magnification but fullscreen magnifier is not registered, it will + * register the magnifier for this call then unregister the magnifier finally to make + * the magnification region correct. + * + * @param displayId The logical display id + * @param outRegion the region to populate + * @param canControlMagnification Whether the service can control magnification + * @return outRegion the magnification bounds of full-screen magnifier or the magnification + * source bounds of window magnifier */ public Region getMagnificationRegion(int displayId, @NonNull Region outRegion, boolean canControlMagnification) { - boolean registeredJustForThisCall = registerMagnificationIfNeeded(displayId, + int mode = getControllingMode(displayId); + if (mode == FULLSCREEN_MODE) { + getFullscreenMagnificationRegion(displayId, outRegion, canControlMagnification); + } else if (mode == WINDOW_MODE) { + mController.getWindowMagnificationMgr().getMagnificationSourceBounds(displayId, + outRegion); + } + return outRegion; + } + + private void getFullscreenMagnificationRegion(int displayId, @NonNull Region outRegion, + boolean canControlMagnification) { + boolean registeredJustForThisCall = registerDisplayMagnificationIfNeeded(displayId, canControlMagnification); try { mController.getFullScreenMagnificationController().getMagnificationRegion(displayId, outRegion); - return outRegion; } finally { if (registeredJustForThisCall) { unregister(displayId); @@ -89,67 +225,105 @@ public class MagnificationProcessor { } } - /** - * {@link FullScreenMagnificationController#setScaleAndCenter(int, float, float, float, boolean, - * int)} - */ - public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY, + private boolean setScaleAndCenterForFullScreenMagnification(int displayId, float scale, + float centerX, float centerY, boolean animate, int id) { if (!isRegistered(displayId)) { register(displayId); } - return mController.getFullScreenMagnificationController().setScaleAndCenter(displayId, + return mController.getFullScreenMagnificationController().setScaleAndCenter( + displayId, scale, centerX, centerY, animate, id); } /** - * {@link FullScreenMagnificationController#reset(int, boolean)} + * Resets the magnification on the given display. The reset mode could be full-screen or + * window if it is activated. + * + * @param displayId The logical display id. + * @param animate {@code true} to animate the transition, {@code false} + * to transition immediately + * @return {@code true} if the magnification spec changed, {@code false} if + * the spec did not change */ public boolean reset(int displayId, boolean animate) { - return mController.getFullScreenMagnificationController().reset(displayId, animate); + int mode = getControllingMode(displayId); + if (mode == FULLSCREEN_MODE) { + return mController.getFullScreenMagnificationController().reset(displayId, animate); + } else if (mode == WINDOW_MODE) { + return mController.getWindowMagnificationMgr().reset(displayId); + } + return false; } /** * {@link FullScreenMagnificationController#resetIfNeeded(int, boolean)} */ + // TODO: support window magnification public void resetAllIfNeeded(int connectionId) { mController.getFullScreenMagnificationController().resetAllIfNeeded(connectionId); } - /** - * {@link FullScreenMagnificationController#register(int)} - */ - public void register(int displayId) { - mController.getFullScreenMagnificationController().register(displayId); - } - - /** - * {@link FullScreenMagnificationController#unregister(int)} (int)} - */ - public void unregister(int displayId) { - mController.getFullScreenMagnificationController().unregister(displayId); - } - /** * {@link FullScreenMagnificationController#isMagnifying(int)} + * {@link WindowMagnificationManager#isWindowMagnifierEnabled(int)} */ public boolean isMagnifying(int displayId) { - return mController.getFullScreenMagnificationController().isMagnifying(displayId); + int mode = getControllingMode(displayId); + if (mode == FULLSCREEN_MODE) { + return mController.getFullScreenMagnificationController().isMagnifying(displayId); + } else if (mode == WINDOW_MODE) { + return mController.getWindowMagnificationMgr().isWindowMagnifierEnabled(displayId); + } + return false; } /** - * {@link FullScreenMagnificationController#isRegistered(int)} + * Returns the current controlling magnification mode on the given display. + * If there is no magnifier activated, it fallbacks to the last activated mode. + * And the last activated mode is {@link FULLSCREEN_MODE} by default. + * + * @param displayId The logical display id */ - public boolean isRegistered(int displayId) { - return mController.getFullScreenMagnificationController().isRegistered(displayId); + public int getControllingMode(int displayId) { + if (mController.isActivated(displayId, + ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW)) { + return WINDOW_MODE; + } else if (mController.isActivated(displayId, + ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN)) { + return FULLSCREEN_MODE; + } else { + return (mController.getLastActivatedMode() == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) + ? WINDOW_MODE + : FULLSCREEN_MODE; + } } - private boolean registerMagnificationIfNeeded(int displayId, boolean canControlMagnification) { + private boolean registerDisplayMagnificationIfNeeded(int displayId, + boolean canControlMagnification) { if (!isRegistered(displayId) && canControlMagnification) { register(displayId); return true; } return false; } + + private boolean isRegistered(int displayId) { + return mController.getFullScreenMagnificationController().isRegistered(displayId); + } + + /** + * {@link FullScreenMagnificationController#register(int)} + */ + private void register(int displayId) { + mController.getFullScreenMagnificationController().register(displayId); + } + + /** + * {@link FullScreenMagnificationController#unregister(int)} (int)} + */ + private void unregister(int displayId) { + mController.getFullScreenMagnificationController().unregister(displayId); + } } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java index e1ec273b444a4..d34b4a9f3ca76 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java @@ -27,6 +27,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Rect; +import android.graphics.Region; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; @@ -271,9 +272,12 @@ public class WindowMagnificationManager implements * or {@link Float#NaN} to leave unchanged. * @param centerY The screen-relative Y coordinate around which to center, * or {@link Float#NaN} to leave unchanged. + * @return {@code true} if the magnification is enabled successfully. */ - void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) { - enableWindowMagnification(displayId, scale, centerX, centerY, STUB_ANIMATION_CALLBACK); + public boolean enableWindowMagnification(int displayId, float scale, float centerX, + float centerY) { + return enableWindowMagnification(displayId, scale, centerX, centerY, + STUB_ANIMATION_CALLBACK); } /** @@ -287,25 +291,29 @@ public class WindowMagnificationManager implements * @param centerY The screen-relative Y coordinate around which to center, * or {@link Float#NaN} to leave unchanged. * @param animationCallback Called when the animation result is valid. + * @return {@code true} if the magnification is enabled successfully. */ - void enableWindowMagnification(int displayId, float scale, float centerX, float centerY, - @Nullable MagnificationAnimationCallback animationCallback) { + public boolean enableWindowMagnification(int displayId, float scale, float centerX, + float centerY, @Nullable MagnificationAnimationCallback animationCallback) { final boolean enabled; + boolean previousEnabled; synchronized (mLock) { if (mConnectionWrapper == null) { - return; + return false; } WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); if (magnifier == null) { magnifier = createWindowMagnifier(displayId); } + previousEnabled = magnifier.mEnabled; enabled = magnifier.enableWindowMagnificationInternal(scale, centerX, centerY, animationCallback); } - if (enabled) { + if (enabled && !previousEnabled) { mCallback.onWindowMagnificationActivationState(displayId, true); } + return enabled; } /** @@ -464,7 +472,7 @@ public class WindowMagnificationManager implements * @param displayId The logical display id * @return the X coordinate. {@link Float#NaN} if the window magnification is not enabled. */ - float getCenterX(int displayId) { + public float getCenterX(int displayId) { synchronized (mLock) { WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); if (magnifier == null) { @@ -480,7 +488,7 @@ public class WindowMagnificationManager implements * @param displayId The logical display id * @return the Y coordinate. {@link Float#NaN} if the window magnification is not enabled. */ - float getCenterY(int displayId) { + public float getCenterY(int displayId) { synchronized (mLock) { WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); if (magnifier == null) { @@ -490,6 +498,42 @@ public class WindowMagnificationManager implements } } + /** + * Populates magnified bounds on the screen. And the populated magnified bounds would be + * empty If window magnifier is not activated. + * + * @param displayId The logical display id. + * @param outRegion the region to populate + */ + public void getMagnificationSourceBounds(int displayId, @NonNull Region outRegion) { + synchronized (mLock) { + WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); + if (magnifier == null) { + outRegion.setEmpty(); + } else { + outRegion.set(magnifier.mSourceBounds); + } + } + } + + /** + * Resets the magnification scale and center. + * + * @param displayId The logical display id. + * @return {@code true} if the magnification spec changed, {@code false} if + * the spec did not change + */ + public boolean reset(int displayId) { + synchronized (mLock) { + WindowMagnifier magnifier = mWindowMagnifiers.get(displayId); + if (magnifier == null) { + return false; + } + magnifier.reset(); + return true; + } + } + /** * Creates the windowMagnifier based on the specified display and stores it. * @@ -626,8 +670,9 @@ public class WindowMagnificationManager implements @GuardedBy("mLock") boolean enableWindowMagnificationInternal(float scale, float centerX, float centerY, @Nullable MagnificationAnimationCallback animationCallback) { - if (mEnabled) { - return false; + // Handle defaults. The scale may be NAN when just updating magnification center. + if (Float.isNaN(scale)) { + scale = getScale(); } final float normScale = MagnificationScaleProvider.constrainScale(scale); if (mWindowMagnificationManager.enableWindowMagnificationInternal(mDisplayId, normScale, 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 086e3c0901a82..a83d51b0e5e7a 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java @@ -68,6 +68,7 @@ import static org.mockito.Mockito.when; import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.AccessibilityTrace; import android.accessibilityservice.IAccessibilityServiceClient; +import android.accessibilityservice.MagnificationConfig; import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -650,8 +651,12 @@ public class AbstractAccessibilityServiceConnectionTest { final float scale = 1.8f; final float centerX = 50.5f; final float centerY = 100.5f; - when(mMockMagnificationProcessor.setScaleAndCenter(displayId, - scale, centerX, centerY, true, SERVICE_ID)).thenReturn(true); + MagnificationConfig config = new MagnificationConfig.Builder() + .setScale(scale) + .setCenterX(centerX) + .setCenterY(centerY).build(); + when(mMockMagnificationProcessor.setMagnificationConfig(displayId, config, true, + SERVICE_ID)).thenReturn(true); when(mMockSecurityPolicy.canControlMagnification(mServiceConnection)).thenReturn(false); final boolean result = mServiceConnection.setMagnificationScaleAndCenter( @@ -665,8 +670,12 @@ public class AbstractAccessibilityServiceConnectionTest { final float scale = 1.8f; final float centerX = 50.5f; final float centerY = 100.5f; - when(mMockMagnificationProcessor.setScaleAndCenter(displayId, - scale, centerX, centerY, true, SERVICE_ID)).thenReturn(true); + MagnificationConfig config = new MagnificationConfig.Builder() + .setScale(scale) + .setCenterX(centerX) + .setCenterY(centerY).build(); + when(mMockMagnificationProcessor.setMagnificationConfig(displayId, config, true, + SERVICE_ID)).thenReturn(true); when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID2); final boolean result = mServiceConnection.setMagnificationScaleAndCenter( 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 c412b94035610..2fd28167df169 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java @@ -16,25 +16,32 @@ package com.android.server.accessibility; +import static android.accessibilityservice.MagnificationConfig.FULLSCREEN_MODE; +import static android.accessibilityservice.MagnificationConfig.WINDOW_MODE; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.accessibilityservice.MagnificationConfig; import android.graphics.Region; import com.android.server.accessibility.magnification.FullScreenMagnificationController; import com.android.server.accessibility.magnification.MagnificationController; import com.android.server.accessibility.magnification.MagnificationProcessor; +import com.android.server.accessibility.magnification.WindowMagnificationManager; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; - +import org.mockito.stubbing.Answer; /** * Tests for the {@link MagnificationProcessor} @@ -42,57 +49,115 @@ import org.mockito.MockitoAnnotations; public class MagnificationProcessorTest { private static final int TEST_DISPLAY = 0; - + private static final int SERVICE_ID = 42; + private static final float TEST_SCALE = 1.8f; + private static final float TEST_CENTER_X = 50.5f; + private static final float TEST_CENTER_Y = 100.5f; private MagnificationProcessor mMagnificationProcessor; @Mock private MagnificationController mMockMagnificationController; @Mock private FullScreenMagnificationController mMockFullScreenMagnificationController; + @Mock + private WindowMagnificationManager mMockWindowMagnificationManager; + FullScreenMagnificationControllerStub mFullScreenMagnificationControllerStub; + WindowMagnificationManagerStub mWindowMagnificationManagerStub; @Before + public void setup() { MockitoAnnotations.initMocks(this); - + mFullScreenMagnificationControllerStub = new FullScreenMagnificationControllerStub( + mMockFullScreenMagnificationController); + mWindowMagnificationManagerStub = new WindowMagnificationManagerStub( + mMockWindowMagnificationManager); when(mMockMagnificationController.getFullScreenMagnificationController()).thenReturn( mMockFullScreenMagnificationController); + when(mMockMagnificationController.getWindowMagnificationMgr()).thenReturn( + mMockWindowMagnificationManager); mMagnificationProcessor = new MagnificationProcessor(mMockMagnificationController); } @Test - public void getScale() { - final float result = 2; - when(mMockFullScreenMagnificationController.getScale(TEST_DISPLAY)).thenReturn(result); + public void getScale_fullscreenMode_expectedValue() { + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(FULLSCREEN_MODE) + .setScale(TEST_SCALE).build(); + setMagnificationActivated(TEST_DISPLAY, config); float scale = mMagnificationProcessor.getScale(TEST_DISPLAY); - assertEquals(scale, result, 0); + assertEquals(scale, TEST_SCALE, 0); } @Test - public void getCenterX_canControlMagnification_returnCenterX() { - final float result = 200; - when(mMockFullScreenMagnificationController.getCenterX(TEST_DISPLAY)).thenReturn(result); + public void getScale_windowMode_expectedValue() { + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(WINDOW_MODE) + .setScale(TEST_SCALE).build(); + setMagnificationActivated(TEST_DISPLAY, config); + + float scale = mMagnificationProcessor.getScale(TEST_DISPLAY); + + assertEquals(scale, TEST_SCALE, 0); + } + + @Test + public void getCenterX_canControlFullscreenMagnification_returnCenterX() { + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(FULLSCREEN_MODE) + .setCenterX(TEST_CENTER_X).build(); + setMagnificationActivated(TEST_DISPLAY, config); float centerX = mMagnificationProcessor.getCenterX( TEST_DISPLAY, /* canControlMagnification= */true); - assertEquals(centerX, result, 0); + assertEquals(centerX, TEST_CENTER_X, 0); } @Test - public void getCenterY_canControlMagnification_returnCenterY() { - final float result = 300; - when(mMockFullScreenMagnificationController.getCenterY(TEST_DISPLAY)).thenReturn(result); + public void getCenterX_canControlWindowMagnification_returnCenterX() { + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(WINDOW_MODE) + .setCenterX(TEST_CENTER_X).build(); + setMagnificationActivated(TEST_DISPLAY, config); + + float centerX = mMagnificationProcessor.getCenterX( + TEST_DISPLAY, /* canControlMagnification= */true); + + assertEquals(centerX, TEST_CENTER_X, 0); + } + + @Test + public void getCenterY_canControlFullscreenMagnification_returnCenterY() { + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(FULLSCREEN_MODE) + .setCenterY(TEST_CENTER_Y).build(); + setMagnificationActivated(TEST_DISPLAY, config); float centerY = mMagnificationProcessor.getCenterY( TEST_DISPLAY, /* canControlMagnification= */false); - assertEquals(centerY, result, 0); + assertEquals(centerY, TEST_CENTER_Y, 0); } @Test - public void getMagnificationRegion_canControlMagnification_returnRegion() { + public void getCenterY_canControlWindowMagnification_returnCenterY() { + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(WINDOW_MODE) + .setCenterY(TEST_CENTER_Y).build(); + setMagnificationActivated(TEST_DISPLAY, config); + + float centerY = mMagnificationProcessor.getCenterY( + TEST_DISPLAY, /* canControlMagnification= */false); + + assertEquals(centerY, TEST_CENTER_Y, 0); + } + + @Test + public void getMagnificationRegion_canControlFullscreenMagnification_returnRegion() { final Region region = new Region(10, 20, 100, 200); + setMagnificationActivated(TEST_DISPLAY, FULLSCREEN_MODE); mMagnificationProcessor.getMagnificationRegion(TEST_DISPLAY, region, /* canControlMagnification= */true); @@ -101,14 +166,25 @@ public class MagnificationProcessorTest { } @Test - public void getMagnificationRegion_notRegistered_shouldRegisterThenUnregister() { + public void getMagnificationRegion_canControlWindowMagnification_returnRegion() { final Region region = new Region(10, 20, 100, 200); + setMagnificationActivated(TEST_DISPLAY, WINDOW_MODE); + mMagnificationProcessor.getMagnificationRegion(TEST_DISPLAY, + region, /* canControlMagnification= */true); + + verify(mMockWindowMagnificationManager).getMagnificationSourceBounds(eq(TEST_DISPLAY), + eq(region)); + } + + @Test + public void getMagnificationRegion_fullscreenModeNotRegistered_shouldRegisterThenUnregister() { + final Region region = new Region(10, 20, 100, 200); + setMagnificationActivated(TEST_DISPLAY, FULLSCREEN_MODE); doAnswer((invocation) -> { ((Region) invocation.getArguments()[1]).set(region); return null; }).when(mMockFullScreenMagnificationController).getMagnificationRegion(eq(TEST_DISPLAY), any()); - when(mMockFullScreenMagnificationController.isRegistered(TEST_DISPLAY)).thenReturn(false); final Region result = new Region(); mMagnificationProcessor.getMagnificationRegion(TEST_DISPLAY, @@ -119,44 +195,242 @@ public class MagnificationProcessorTest { } @Test - public void getMagnificationCenterX_notRegistered_shouldRegisterThenUnregister() { - final float centerX = 480.0f; - when(mMockFullScreenMagnificationController.getCenterX(TEST_DISPLAY)).thenReturn(centerX); - when(mMockFullScreenMagnificationController.isRegistered(TEST_DISPLAY)).thenReturn(false); + public void getMagnificationCenterX_fullscreenModeNotRegistered_shouldRegisterThenUnregister() { + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(FULLSCREEN_MODE) + .setCenterX(TEST_CENTER_X).build(); + setMagnificationActivated(TEST_DISPLAY, config); final float result = mMagnificationProcessor.getCenterX( TEST_DISPLAY, /* canControlMagnification= */ true); - assertEquals(centerX, result, 0); + assertEquals(TEST_CENTER_X, result, 0); verify(mMockFullScreenMagnificationController).register(TEST_DISPLAY); verify(mMockFullScreenMagnificationController).unregister(TEST_DISPLAY); } @Test - public void getMagnificationCenterY_notRegistered_shouldRegisterThenUnregister() { - final float centerY = 640.0f; - when(mMockFullScreenMagnificationController.getCenterY(TEST_DISPLAY)).thenReturn(centerY); - when(mMockFullScreenMagnificationController.isRegistered(TEST_DISPLAY)).thenReturn(false); + public void getMagnificationCenterY_fullscreenModeNotRegistered_shouldRegisterThenUnregister() { + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(FULLSCREEN_MODE) + .setCenterY(TEST_CENTER_Y).build(); + setMagnificationActivated(TEST_DISPLAY, config); final float result = mMagnificationProcessor.getCenterY( TEST_DISPLAY, /* canControlMagnification= */ true); - assertEquals(centerY, result, 0); + assertEquals(TEST_CENTER_Y, result, 0); verify(mMockFullScreenMagnificationController).register(TEST_DISPLAY); verify(mMockFullScreenMagnificationController).unregister(TEST_DISPLAY); } @Test - public void setMagnificationScaleAndCenter_notRegistered_shouldRegister() { - final int serviceId = 42; - final float scale = 1.8f; - final float centerX = 50.5f; - final float centerY = 100.5f; - when(mMockFullScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY, - scale, centerX, centerY, true, serviceId)).thenReturn(true); - when(mMockFullScreenMagnificationController.isRegistered(TEST_DISPLAY)).thenReturn(false); + public void getCurrentMode_configDefaultMode_returnActivatedMode() { + final int targetMode = WINDOW_MODE; + setMagnificationActivated(TEST_DISPLAY, targetMode); - final boolean result = mMagnificationProcessor.setScaleAndCenter( - TEST_DISPLAY, scale, centerX, centerY, true, serviceId); + int currentMode = mMagnificationProcessor.getControllingMode(TEST_DISPLAY); + + assertEquals(WINDOW_MODE, currentMode); + } + + @Test + public void reset_fullscreenMagnificationActivated() { + setMagnificationActivated(TEST_DISPLAY, FULLSCREEN_MODE); + + mMagnificationProcessor.reset(TEST_DISPLAY, /* animate= */false); + + verify(mMockFullScreenMagnificationController).reset(TEST_DISPLAY, false); + } + + @Test + public void reset_windowMagnificationActivated() { + setMagnificationActivated(TEST_DISPLAY, WINDOW_MODE); + + mMagnificationProcessor.reset(TEST_DISPLAY, /* animate= */false); + + verify(mMockWindowMagnificationManager).reset(TEST_DISPLAY); + } + + @Test + public void setMagnificationConfig_fullscreenModeNotRegistered_shouldRegister() { + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(FULLSCREEN_MODE) + .setScale(TEST_SCALE) + .setCenterX(TEST_CENTER_X) + .setCenterY(TEST_CENTER_Y).build(); + setMagnificationActivated(TEST_DISPLAY, config); + + final boolean result = mMagnificationProcessor.setMagnificationConfig( + TEST_DISPLAY, config, true, SERVICE_ID); assertTrue(result); verify(mMockFullScreenMagnificationController).register(TEST_DISPLAY); } + + @Test + public void setMagnificationConfig_windowMode_enableMagnification() { + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(WINDOW_MODE) + .setScale(TEST_SCALE) + .setCenterX(TEST_CENTER_X) + .setCenterY(TEST_CENTER_Y).build(); + setMagnificationActivated(TEST_DISPLAY, config); + + final boolean result = mMagnificationProcessor.setMagnificationConfig( + TEST_DISPLAY, config, true, SERVICE_ID); + + assertTrue(result); + } + + @Test + public void setMagnificationConfig_fullscreenEnabled_expectedConfigValues() { + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(FULLSCREEN_MODE) + .setScale(TEST_SCALE) + .setCenterX(TEST_CENTER_X) + .setCenterY(TEST_CENTER_Y).build(); + setMagnificationActivated(TEST_DISPLAY, config); + // mMockFullScreenMagnificationController.unregister(TEST_DISPLAY); + mMagnificationProcessor.setMagnificationConfig( + TEST_DISPLAY, config, true, SERVICE_ID); + + final MagnificationConfig result = mMagnificationProcessor.getMagnificationConfig( + TEST_DISPLAY); + + assertConfigEquals(config, result); + } + + @Test + public void setMagnificationConfig_windowEnabled_expectedConfigValues() { + final MagnificationConfig config = new MagnificationConfig.Builder() + .setMode(WINDOW_MODE) + .setScale(TEST_SCALE) + .setCenterX(TEST_CENTER_X) + .setCenterY(TEST_CENTER_Y).build(); + setMagnificationActivated(TEST_DISPLAY, config); + + mMagnificationProcessor.setMagnificationConfig( + TEST_DISPLAY, config, true, SERVICE_ID); + + final MagnificationConfig result = mMagnificationProcessor.getMagnificationConfig( + TEST_DISPLAY); + + assertConfigEquals(config, result); + } + + private void setMagnificationActivated(int displayId, int configMode) { + setMagnificationActivated(displayId, + new MagnificationConfig.Builder().setMode(configMode).build()); + } + + private void setMagnificationActivated(int displayId, MagnificationConfig config) { + when(mMockMagnificationController.isActivated(displayId, config.getMode())).thenReturn( + true); + mMagnificationProcessor.setMagnificationConfig(displayId, config, false, SERVICE_ID); + if (config.getMode() == FULLSCREEN_MODE) { + when(mMockMagnificationController.isActivated(displayId, WINDOW_MODE)).thenReturn( + false); + mFullScreenMagnificationControllerStub.resetAndStubMethods(); + mMockFullScreenMagnificationController.setScaleAndCenter(displayId, config.getScale(), + config.getCenterX(), config.getCenterY(), true, SERVICE_ID); + } else if (config.getMode() == WINDOW_MODE) { + when(mMockMagnificationController.isActivated(displayId, FULLSCREEN_MODE)).thenReturn( + false); + mWindowMagnificationManagerStub.resetAndStubMethods(); + mMockWindowMagnificationManager.enableWindowMagnification(displayId, config.getScale(), + config.getCenterX(), config.getCenterY()); + } + } + + private void assertConfigEquals(MagnificationConfig expected, MagnificationConfig actual) { + assertEquals(expected.getMode(), actual.getMode()); + assertEquals(expected.getScale(), actual.getScale(), 0); + assertEquals(expected.getCenterX(), actual.getCenterX(), 0); + assertEquals(expected.getCenterY(), actual.getCenterY(), 0); + } + + private static class FullScreenMagnificationControllerStub { + private final FullScreenMagnificationController mScreenMagnificationController; + private float mScale = 1.0f; + private float mCenterX = 0; + private float mCenterY = 0; + private boolean mIsRegistered = false; + + FullScreenMagnificationControllerStub( + FullScreenMagnificationController screenMagnificationController) { + mScreenMagnificationController = screenMagnificationController; + } + + private void stubMethods() { + doAnswer(invocation -> mScale).when(mScreenMagnificationController).getScale( + TEST_DISPLAY); + doAnswer(invocation -> mCenterX).when(mScreenMagnificationController).getCenterX( + TEST_DISPLAY); + doAnswer(invocation -> mCenterY).when(mScreenMagnificationController).getCenterY( + TEST_DISPLAY); + doAnswer(invocation -> mIsRegistered).when(mScreenMagnificationController).isRegistered( + TEST_DISPLAY); + Answer enableMagnificationStubAnswer = invocation -> { + mScale = invocation.getArgument(1); + mCenterX = invocation.getArgument(2); + mCenterY = invocation.getArgument(3); + return true; + }; + doAnswer(enableMagnificationStubAnswer).when( + mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY), anyFloat(), + anyFloat(), anyFloat(), eq(true), eq(SERVICE_ID)); + + Answer registerStubAnswer = invocation -> { + mIsRegistered = true; + return true; + }; + doAnswer(registerStubAnswer).when( + mScreenMagnificationController).register(eq(TEST_DISPLAY)); + + Answer unregisterStubAnswer = invocation -> { + mIsRegistered = false; + return true; + }; + doAnswer(unregisterStubAnswer).when( + mScreenMagnificationController).unregister(eq(TEST_DISPLAY)); + } + + public void resetAndStubMethods() { + Mockito.reset(mScreenMagnificationController); + stubMethods(); + } + } + + private static class WindowMagnificationManagerStub { + private final WindowMagnificationManager mWindowMagnificationManager; + private float mScale = 1.0f; + private float mCenterX = 0; + private float mCenterY = 0; + + WindowMagnificationManagerStub( + WindowMagnificationManager windowMagnificationManager) { + mWindowMagnificationManager = windowMagnificationManager; + } + + private void stubMethods() { + doAnswer(invocation -> mScale).when(mWindowMagnificationManager).getScale( + TEST_DISPLAY); + doAnswer(invocation -> mCenterX).when(mWindowMagnificationManager).getCenterX( + TEST_DISPLAY); + doAnswer(invocation -> mCenterY).when(mWindowMagnificationManager).getCenterY( + TEST_DISPLAY); + Answer enableWindowMagnificationStubAnswer = invocation -> { + mScale = invocation.getArgument(1); + mCenterX = invocation.getArgument(2); + mCenterY = invocation.getArgument(3); + return true; + }; + doAnswer(enableWindowMagnificationStubAnswer).when( + mWindowMagnificationManager).enableWindowMagnification(eq(TEST_DISPLAY), + anyFloat(), anyFloat(), anyFloat()); + } + + public void resetAndStubMethods() { + Mockito.reset(mWindowMagnificationManager); + stubMethods(); + } + } } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java index 15ba358f146e3..02c0aca5c7773 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java @@ -376,6 +376,17 @@ public class WindowMagnificationManagerTest { verify(mContext).unregisterReceiver(any(BroadcastReceiver.class)); } + @Test + public void resetMagnification_enabled_windowMagnifierDisabled() { + mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); + mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN); + assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY)); + + mWindowMagnificationManager.reset(TEST_DISPLAY); + + assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY)); + } + @Test public void onScreenOff_windowMagnifierIsEnabled_removeButtonAndDisableWindowMagnification() throws RemoteException {