From 3f09839e1dee4a3cabad3f300a2a78b897631d09 Mon Sep 17 00:00:00 2001 From: Roy Chou Date: Fri, 14 Apr 2023 09:06:25 +0000 Subject: [PATCH 1/4] chore(#Magnification): add MagnificationFeatureFlagBase We'll add thumbnail feature flag in next cl and joystick feature flag in the future. These feature flag files are almost same as AlwaysOnMagnificationFeatureFlag, just in difference on namespace and feature name. Therefore, we add a feature flag base file to handle the logics, so that the extended feature flag files can share the base codes and customize namespace and feature name on its own. In MagnificationFeatureFlagBase, we would clear binder identity, then access the DEVICE_CONFIG with given namespace. It's to prevent permission denied exceptions. we would restore the identity after the access. Bug: 276979625 Test: manually atest MagnificationControllerTest Change-Id: I2857cd332bd98726718cf5b5913e6eccf741c3da --- .../AlwaysOnMagnificationFeatureFlag.java | 65 ++-------- .../MagnificationController.java | 6 +- .../MagnificationFeatureFlagBase.java | 115 ++++++++++++++++++ 3 files changed, 129 insertions(+), 57 deletions(-) create mode 100644 services/accessibility/java/com/android/server/accessibility/magnification/MagnificationFeatureFlagBase.java diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/AlwaysOnMagnificationFeatureFlag.java b/services/accessibility/java/com/android/server/accessibility/magnification/AlwaysOnMagnificationFeatureFlag.java index 16d2e6b47a54c..93531ddea005b 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/AlwaysOnMagnificationFeatureFlag.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/AlwaysOnMagnificationFeatureFlag.java @@ -16,76 +16,31 @@ package com.android.server.accessibility.magnification; -import android.annotation.NonNull; import android.provider.DeviceConfig; -import com.android.internal.annotations.VisibleForTesting; - -import java.util.concurrent.Executor; - /** * Encapsulates the feature flags for always on magnification. {@see DeviceConfig} * * @hide */ -public class AlwaysOnMagnificationFeatureFlag { +public class AlwaysOnMagnificationFeatureFlag extends MagnificationFeatureFlagBase { private static final String NAMESPACE = DeviceConfig.NAMESPACE_WINDOW_MANAGER; private static final String FEATURE_NAME_ENABLE_ALWAYS_ON_MAGNIFICATION = "AlwaysOnMagnifier__enable_always_on_magnifier"; - private AlwaysOnMagnificationFeatureFlag() {} - - /** Returns true if the feature flag is enabled for always on magnification */ - public static boolean isAlwaysOnMagnificationEnabled() { - return DeviceConfig.getBoolean( - NAMESPACE, - FEATURE_NAME_ENABLE_ALWAYS_ON_MAGNIFICATION, - /* defaultValue= */ false); + @Override + String getNamespace() { + return NAMESPACE; } - /** Sets the feature flag. Only used for testing; requires shell permissions. */ - @VisibleForTesting - public static boolean setAlwaysOnMagnificationEnabled(boolean isEnabled) { - return DeviceConfig.setProperty( - NAMESPACE, - FEATURE_NAME_ENABLE_ALWAYS_ON_MAGNIFICATION, - Boolean.toString(isEnabled), - /* makeDefault= */ false); + @Override + String getFeatureName() { + return FEATURE_NAME_ENABLE_ALWAYS_ON_MAGNIFICATION; } - /** - * Adds a listener for when the feature flag changes. - * - *

{@see DeviceConfig#addOnPropertiesChangedListener( - * String, Executor, DeviceConfig.OnPropertiesChangedListener)} - */ - @NonNull - public static DeviceConfig.OnPropertiesChangedListener addOnChangedListener( - @NonNull Executor executor, @NonNull Runnable listener) { - DeviceConfig.OnPropertiesChangedListener onChangedListener = - properties -> { - if (properties.getKeyset().contains( - FEATURE_NAME_ENABLE_ALWAYS_ON_MAGNIFICATION)) { - listener.run(); - } - }; - DeviceConfig.addOnPropertiesChangedListener( - NAMESPACE, - executor, - onChangedListener); - - return onChangedListener; - } - - /** - * Remove a listener for when the feature flag changes. - * - *

{@see DeviceConfig#addOnPropertiesChangedListener(String, Executor, - * DeviceConfig.OnPropertiesChangedListener)} - */ - public static void removeOnChangedListener( - @NonNull DeviceConfig.OnPropertiesChangedListener onChangedListener) { - DeviceConfig.removeOnPropertiesChangedListener(onChangedListener); + @Override + boolean getDefaultValue() { + return false; } } 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 22e742bc09731..1055ba23b10fe 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java @@ -93,6 +93,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb private final SparseArray mMagnificationEndRunnableSparseArray = new SparseArray(); + private final AlwaysOnMagnificationFeatureFlag mAlwaysOnMagnificationFeatureFlag; private final MagnificationScaleProvider mScaleProvider; private FullScreenMagnificationController mFullScreenMagnificationController; private WindowMagnificationManager mWindowMagnificationMgr; @@ -151,7 +152,8 @@ public class MagnificationController implements WindowMagnificationManager.Callb mSupportWindowMagnification = context.getPackageManager().hasSystemFeature( FEATURE_WINDOW_MAGNIFICATION); - AlwaysOnMagnificationFeatureFlag.addOnChangedListener( + mAlwaysOnMagnificationFeatureFlag = new AlwaysOnMagnificationFeatureFlag(); + mAlwaysOnMagnificationFeatureFlag.addOnChangedListener( ConcurrentUtils.DIRECT_EXECUTOR, mAms::updateAlwaysOnMagnification); } @@ -698,7 +700,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb } public boolean isAlwaysOnMagnificationFeatureFlagEnabled() { - return AlwaysOnMagnificationFeatureFlag.isAlwaysOnMagnificationEnabled(); + return mAlwaysOnMagnificationFeatureFlag.isFeatureFlagEnabled(); } private DisableMagnificationCallback getDisableMagnificationEndRunnableLocked( diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationFeatureFlagBase.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationFeatureFlagBase.java new file mode 100644 index 0000000000000..2965887d8eb3c --- /dev/null +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationFeatureFlagBase.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2023 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 com.android.server.accessibility.magnification; + +import android.annotation.NonNull; +import android.os.Binder; +import android.provider.DeviceConfig; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Abstract base class to encapsulates the feature flags for magnification features. + * {@see DeviceConfig} + * + * @hide + */ +abstract class MagnificationFeatureFlagBase { + + abstract String getNamespace(); + abstract String getFeatureName(); + abstract boolean getDefaultValue(); + + private void clearCallingIdentifyAndTryCatch(Runnable tryBlock, Runnable catchBlock) { + try { + Binder.withCleanCallingIdentity(() -> tryBlock.run()); + } catch (Throwable throwable) { + catchBlock.run(); + } + } + + /** Returns true iff the feature flag is readable and enabled */ + public boolean isFeatureFlagEnabled() { + AtomicBoolean isEnabled = new AtomicBoolean(getDefaultValue()); + + clearCallingIdentifyAndTryCatch( + () -> isEnabled.set(DeviceConfig.getBoolean( + getNamespace(), + getFeatureName(), + getDefaultValue())), + () -> isEnabled.set(getDefaultValue())); + + return isEnabled.get(); + } + + /** Sets the feature flag. Only used for testing; requires shell permissions. */ + @VisibleForTesting + public boolean setFeatureFlagEnabled(boolean isEnabled) { + AtomicBoolean success = new AtomicBoolean(getDefaultValue()); + + clearCallingIdentifyAndTryCatch( + () -> success.set(DeviceConfig.setProperty( + getNamespace(), + getFeatureName(), + Boolean.toString(isEnabled), + /* makeDefault= */ false)), + () -> success.set(getDefaultValue())); + + return success.get(); + } + + /** + * Adds a listener for when the feature flag changes. + * + *

{@see DeviceConfig#addOnPropertiesChangedListener( + * String, Executor, DeviceConfig.OnPropertiesChangedListener)} + */ + @NonNull + public DeviceConfig.OnPropertiesChangedListener addOnChangedListener( + @NonNull Executor executor, @NonNull Runnable listener) { + DeviceConfig.OnPropertiesChangedListener onChangedListener = + properties -> { + if (properties.getKeyset().contains( + getFeatureName())) { + listener.run(); + } + }; + + clearCallingIdentifyAndTryCatch( + () -> DeviceConfig.addOnPropertiesChangedListener( + getNamespace(), + executor, + onChangedListener), + () -> {}); + + return onChangedListener; + } + + /** + * Remove a listener for when the feature flag changes. + * + *

{@see DeviceConfig#addOnPropertiesChangedListener(String, Executor, + * DeviceConfig.OnPropertiesChangedListener)} + */ + public void removeOnChangedListener( + @NonNull DeviceConfig.OnPropertiesChangedListener onChangedListener) { + DeviceConfig.removeOnPropertiesChangedListener(onChangedListener); + } +} From c5c1eb4d50c39700b1ccdd1de4837b524ada5cf7 Mon Sep 17 00:00:00 2001 From: Roy Chou Date: Mon, 17 Apr 2023 14:08:30 +0000 Subject: [PATCH 2/4] chore(#MagnificationThumbnail): add feature flag file and fix size not correct sometimes We add MagnificationThumbnailFeatureFlag to encapsulates the feature flag from directly access in FullScreenMagnificationController. MagnificationThumbnailFeatureFlag is extended from MagnificationFeatureFlagBase so we can clear binder identity before access the flag. Besides, FullScreenMagnificationController can observe feature flag flips and create/destroy the thumbnail. Originally the thumbnail size would be huge sometimes. It's because the thumbnail layout size is not updated properly based on the magnification bounds before it shows on screen. Therefore, we call refreshThumbnail to update the size when the thumbnail is just created in FullScreenMagnificationController. Bug: 276979625 Bug: 276314641 Test: manually test with adb to flip the flag atest FullScreenMagnificationControllerTest Change-Id: I1480b73454ad32f2a294bace56a285ae462119d8 --- .../FullScreenMagnificationController.java | 98 +++++++++++++------ .../MagnificationThumbnailFeatureFlag.java | 46 +++++++++ ...FullScreenMagnificationControllerTest.java | 5 +- 3 files changed, 118 insertions(+), 31 deletions(-) create mode 100644 services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnailFeatureFlag.java diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java index ed8a35f45176e..e78a9fd7ad0cd 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java @@ -38,7 +38,6 @@ import android.graphics.Region; import android.hardware.display.DisplayManagerInternal; import android.os.Handler; import android.os.Message; -import android.provider.DeviceConfig; import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.MathUtils; @@ -57,6 +56,7 @@ import com.android.internal.R; import com.android.internal.accessibility.common.MagnificationConstants; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.accessibility.AccessibilityManagerService; @@ -110,6 +110,7 @@ public class FullScreenMagnificationController implements private boolean mAlwaysOnMagnificationEnabled = false; private final DisplayManagerInternal mDisplayManagerInternal; + private final MagnificationThumbnailFeatureFlag mMagnificationThumbnailFeatureFlag; @NonNull private final Supplier mThumbnailSupplier; /** @@ -177,9 +178,7 @@ public class FullScreenMagnificationController implements mDisplayId, mMagnificationRegion); mMagnificationRegion.getBounds(mMagnificationBounds); - if (mMagnificationThumbnail == null) { - mMagnificationThumbnail = mThumbnailSupplier.get(); - } + createThumbnailIfSupported(); return true; } @@ -207,7 +206,7 @@ public class FullScreenMagnificationController implements mRegistered = false; unregisterCallbackLocked(mDisplayId, delete); - destroyThumbNail(); + destroyThumbnail(); } mUnregisterPending = false; } @@ -345,7 +344,7 @@ public class FullScreenMagnificationController implements mMagnificationRegion.set(magnified); mMagnificationRegion.getBounds(mMagnificationBounds); - refreshThumbNail(getScale(), getCenterX(), getCenterY()); + refreshThumbnail(getScale(), getCenterX(), getCenterY()); // It's possible that our magnification spec is invalid with the new bounds. // Adjust the current spec's offsets if necessary. @@ -405,9 +404,9 @@ public class FullScreenMagnificationController implements } if (isActivated()) { - updateThumbNail(scale, centerX, centerY); + updateThumbnail(scale, centerX, centerY); } else { - hideThumbNail(); + hideThumbnail(); } } @@ -538,7 +537,7 @@ public class FullScreenMagnificationController implements mIdOfLastServiceToMagnify = INVALID_SERVICE_ID; sendSpecToAnimation(spec, animationCallback); - hideThumbNail(); + hideThumbnail(); return changed; } @@ -596,14 +595,14 @@ public class FullScreenMagnificationController implements } @GuardedBy("mLock") - void updateThumbNail(float scale, float centerX, float centerY) { + void updateThumbnail(float scale, float centerX, float centerY) { if (mMagnificationThumbnail != null) { mMagnificationThumbnail.updateThumbNail(scale, centerX, centerY); } } @GuardedBy("mLock") - void refreshThumbNail(float scale, float centerX, float centerY) { + void refreshThumbnail(float scale, float centerX, float centerY) { if (mMagnificationThumbnail != null) { mMagnificationThumbnail.setThumbNailBounds( mMagnificationBounds, @@ -615,20 +614,38 @@ public class FullScreenMagnificationController implements } @GuardedBy("mLock") - void hideThumbNail() { + void hideThumbnail() { if (mMagnificationThumbnail != null) { mMagnificationThumbnail.hideThumbNail(); } } @GuardedBy("mLock") - void destroyThumbNail() { + void createThumbnailIfSupported() { + if (mMagnificationThumbnail == null) { + mMagnificationThumbnail = mThumbnailSupplier.get(); + // We call refreshThumbnail when the thumbnail is just created to set current + // magnification bounds to thumbnail. It to prevent the thumbnail size has not yet + // updated properly and thus shows with huge size. (b/276314641) + refreshThumbnail(getScale(), getCenterX(), getCenterY()); + } + } + + @GuardedBy("mLock") + void destroyThumbnail() { if (mMagnificationThumbnail != null) { - hideThumbNail(); + hideThumbnail(); mMagnificationThumbnail = null; } } + void onThumbnailFeatureFlagChanged() { + synchronized (mLock) { + destroyThumbnail(); + createThumbnailIfSupported(); + } + } + /** * Updates the current magnification spec. * @@ -768,20 +785,7 @@ public class FullScreenMagnificationController implements lock, magnificationInfoChangedCallback, scaleProvider, - () -> { - if (DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_ACCESSIBILITY, - "enable_magnifier_thumbnail", - /* defaultValue= */ false)) { - return new MagnificationThumbnail( - context, - context.getSystemService(WindowManager.class), - new Handler(context.getMainLooper()) - ); - } - - return null; - }); + /* thumbnailSupplier= */ null); } /** Constructor for tests */ @@ -791,7 +795,7 @@ public class FullScreenMagnificationController implements @NonNull Object lock, @NonNull MagnificationInfoChangedCallback magnificationInfoChangedCallback, @NonNull MagnificationScaleProvider scaleProvider, - @NonNull Supplier thumbnailSupplier) { + Supplier thumbnailSupplier) { mControllerCtx = ctx; mLock = lock; mMainThreadId = mControllerCtx.getContext().getMainLooper().getThread().getId(); @@ -799,7 +803,41 @@ public class FullScreenMagnificationController implements addInfoChangedCallback(magnificationInfoChangedCallback); mScaleProvider = scaleProvider; mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); - mThumbnailSupplier = thumbnailSupplier; + mMagnificationThumbnailFeatureFlag = new MagnificationThumbnailFeatureFlag(); + mMagnificationThumbnailFeatureFlag.addOnChangedListener( + ConcurrentUtils.DIRECT_EXECUTOR, this::onMagnificationThumbnailFeatureFlagChanged); + if (thumbnailSupplier != null) { + mThumbnailSupplier = thumbnailSupplier; + } else { + mThumbnailSupplier = () -> { + if (mMagnificationThumbnailFeatureFlag.isFeatureFlagEnabled()) { + return new MagnificationThumbnail( + ctx.getContext(), + ctx.getContext().getSystemService(WindowManager.class), + new Handler(ctx.getContext().getMainLooper()) + ); + } + return null; + }; + } + } + + private void onMagnificationThumbnailFeatureFlagChanged() { + synchronized (mLock) { + for (int i = 0; i < mDisplays.size(); i++) { + onMagnificationThumbnailFeatureFlagChanged(mDisplays.keyAt(i)); + } + } + } + + private void onMagnificationThumbnailFeatureFlagChanged(int displayId) { + synchronized (mLock) { + final DisplayMagnification display = mDisplays.get(displayId); + if (display == null) { + return; + } + display.onThumbnailFeatureFlagChanged(); + } } /** diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnailFeatureFlag.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnailFeatureFlag.java new file mode 100644 index 0000000000000..519f31b86f78a --- /dev/null +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnailFeatureFlag.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023 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 com.android.server.accessibility.magnification; + +import android.provider.DeviceConfig; + +/** + * Encapsulates the feature flags for magnification thumbnail. {@see DeviceConfig} + * + * @hide + */ +public class MagnificationThumbnailFeatureFlag extends MagnificationFeatureFlagBase { + + private static final String NAMESPACE = DeviceConfig.NAMESPACE_ACCESSIBILITY; + private static final String FEATURE_NAME_ENABLE_MAGNIFIER_THUMBNAIL = + "enable_magnifier_thumbnail"; + + @Override + String getNamespace() { + return NAMESPACE; + } + + @Override + String getFeatureName() { + return FEATURE_NAME_ENABLE_MAGNIFIER_THUMBNAIL; + } + + @Override + boolean getDefaultValue() { + return false; + } +} diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java index f1ad577fde885..35fc40cb60a69 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java @@ -538,7 +538,10 @@ public class FullScreenMagnificationControllerTest { mConfigCaptor.capture()); assertConfigEquals(config, mConfigCaptor.getValue()); - verify(mMockThumbnail).setThumbNailBounds(any(), anyFloat(), anyFloat(), anyFloat()); + // The first time is triggered when the thumbnail is just created. + // The second time is triggered when the magnification region changed. + verify(mMockThumbnail, times(2)).setThumbNailBounds( + any(), anyFloat(), anyFloat(), anyFloat()); } @Test From eaab4f2517c48157bdeca328ee49af80c39c9025 Mon Sep 17 00:00:00 2001 From: Roy Chou Date: Mon, 17 Apr 2023 14:49:35 +0000 Subject: [PATCH 3/4] fix(#MagnificationThumbnail): thumbnail magnifying area position is not correct sometimes In MagnificationThumbnail, mThumbnailView size is 0 when the layout has not added to windowManager ever, and thus the magnifying area position x/y calculations would not be correct. Therefore, we use the magnification bounds to calculate the estimated size if the size is 0. If the mThumbnailView is added to window and its size is update properly, we can use the real size to calculate the magfying area x/y after. Bug: 278509054 Test: manually atest MagnificationThumbnailTest Change-Id: Ifdc84b178e264694061b3b15cbb496ab8f0374b3 --- .../magnification/MagnificationThumbnail.java | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnail.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnail.java index 5a783f47ccdc9..f3c62c63a7d57 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnail.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnail.java @@ -59,6 +59,8 @@ public class MagnificationThumbnail { public final FrameLayout mThumbnailLayout; private final View mThumbNailView; + private int mThumbnailWidth; + private int mThumbnailHeight; private final WindowManager.LayoutParams mBackgroundParams; private boolean mVisible = false; @@ -82,6 +84,8 @@ public class MagnificationThumbnail { mThumbNailView = mThumbnailLayout.findViewById(R.id.accessibility_magnification_thumbnail_view); mBackgroundParams = createLayoutParams(); + mThumbnailWidth = 0; + mThumbnailHeight = 0; } /** @@ -105,12 +109,12 @@ public class MagnificationThumbnail { private void setBackgroundBounds() { Point magnificationBoundary = getMagnificationThumbnailPadding(mContext); - final int thumbNailWidth = (int) (mWindowBounds.width() / BG_ASPECT_RATIO); - final int thumbNailHeight = (int) (mWindowBounds.height() / BG_ASPECT_RATIO); + mThumbnailWidth = (int) (mWindowBounds.width() / BG_ASPECT_RATIO); + mThumbnailHeight = (int) (mWindowBounds.height() / BG_ASPECT_RATIO); int initX = magnificationBoundary.x; int initY = magnificationBoundary.y; - mBackgroundParams.width = thumbNailWidth; - mBackgroundParams.height = thumbNailHeight; + mBackgroundParams.width = mThumbnailWidth; + mBackgroundParams.height = mThumbnailHeight; mBackgroundParams.x = initX; mBackgroundParams.y = initY; } @@ -260,11 +264,21 @@ public class MagnificationThumbnail { mThumbNailView.setScaleX(scaleDown); mThumbNailView.setScaleY(scaleDown); } + float thumbnailWidth; + float thumbnailHeight; + if (mThumbNailView.getWidth() == 0 || mThumbNailView.getHeight() == 0) { + // if the thumbnail view size is not updated correctly, we just use the cached values. + thumbnailWidth = mThumbnailWidth; + thumbnailHeight = mThumbnailHeight; + } else { + thumbnailWidth = mThumbNailView.getWidth(); + thumbnailHeight = mThumbNailView.getHeight(); + } if (!Float.isNaN(centerX)) { var padding = mThumbNailView.getPaddingTop(); var ratio = 1f / BG_ASPECT_RATIO; - var centerXScaled = centerX * ratio - (mThumbNailView.getWidth() / 2f + padding); - var centerYScaled = centerY * ratio - (mThumbNailView.getHeight() / 2f + padding); + var centerXScaled = centerX * ratio - (thumbnailWidth / 2f + padding); + var centerYScaled = centerY * ratio - (thumbnailHeight / 2f + padding); if (DEBUG) { Log.d( From c6e7e2b9c7bd733faf5ac096aba247a78117389c Mon Sep 17 00:00:00 2001 From: Roy Chou Date: Mon, 17 Apr 2023 15:41:33 +0000 Subject: [PATCH 4/4] chore(#MagnificationThumbnail): rename thumbNail to thumbnail Rename thumbNail to thumbnail to make camelcase consistency in magnification. Bug: 278646377 Test: pass the make atest FullScreenMagnificationControllerTest atest MagnificationThumbnailTest Change-Id: Iaf1ecb67e7ece8e63310afe830e410d0c23b3bdc --- .../FullScreenMagnificationController.java | 6 +- .../magnification/MagnificationThumbnail.java | 72 +++++++++---------- ...FullScreenMagnificationControllerTest.java | 6 +- .../MagnificationThumbnailTest.java | 24 +++---- 4 files changed, 54 insertions(+), 54 deletions(-) diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java index e78a9fd7ad0cd..fbc7b3cbc63b1 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java @@ -597,14 +597,14 @@ public class FullScreenMagnificationController implements @GuardedBy("mLock") void updateThumbnail(float scale, float centerX, float centerY) { if (mMagnificationThumbnail != null) { - mMagnificationThumbnail.updateThumbNail(scale, centerX, centerY); + mMagnificationThumbnail.updateThumbnail(scale, centerX, centerY); } } @GuardedBy("mLock") void refreshThumbnail(float scale, float centerX, float centerY) { if (mMagnificationThumbnail != null) { - mMagnificationThumbnail.setThumbNailBounds( + mMagnificationThumbnail.setThumbnailBounds( mMagnificationBounds, scale, centerX, @@ -616,7 +616,7 @@ public class FullScreenMagnificationController implements @GuardedBy("mLock") void hideThumbnail() { if (mMagnificationThumbnail != null) { - mMagnificationThumbnail.hideThumbNail(); + mMagnificationThumbnail.hideThumbnail(); } } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnail.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnail.java index f3c62c63a7d57..03fa93d8a3bc4 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnail.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnail.java @@ -58,7 +58,7 @@ public class MagnificationThumbnail { @VisibleForTesting public final FrameLayout mThumbnailLayout; - private final View mThumbNailView; + private final View mThumbnailView; private int mThumbnailWidth; private int mThumbnailHeight; @@ -68,7 +68,7 @@ public class MagnificationThumbnail { private static final float ASPECT_RATIO = 14f; private static final float BG_ASPECT_RATIO = ASPECT_RATIO / 2f; - private ObjectAnimator mThumbNailAnimator; + private ObjectAnimator mThumbnailAnimator; private boolean mIsFadingIn; /** @@ -81,7 +81,7 @@ public class MagnificationThumbnail { mWindowBounds = mWindowManager.getCurrentWindowMetrics().getBounds(); mThumbnailLayout = (FrameLayout) LayoutInflater.from(mContext) .inflate(R.layout.thumbnail_background_view, /* root: */ null); - mThumbNailView = + mThumbnailView = mThumbnailLayout.findViewById(R.id.accessibility_magnification_thumbnail_view); mBackgroundParams = createLayoutParams(); mThumbnailWidth = 0; @@ -94,15 +94,15 @@ public class MagnificationThumbnail { * @param currentBounds the current magnification bounds */ @AnyThread - public void setThumbNailBounds(Rect currentBounds, float scale, float centerX, float centerY) { + public void setThumbnailBounds(Rect currentBounds, float scale, float centerX, float centerY) { if (DEBUG) { - Log.d(LOG_TAG, "setThumbNailBounds " + currentBounds); + Log.d(LOG_TAG, "setThumbnailBounds " + currentBounds); } mHandler.post(() -> { mWindowBounds = currentBounds; setBackgroundBounds(); if (mVisible) { - updateThumbNailMainThread(scale, centerX, centerY); + updateThumbnailMainThread(scale, centerX, centerY); } }); } @@ -120,9 +120,9 @@ public class MagnificationThumbnail { } @MainThread - private void showThumbNail() { + private void showThumbnail() { if (DEBUG) { - Log.d(LOG_TAG, "showThumbNail " + mVisible); + Log.d(LOG_TAG, "showThumbnail " + mVisible); } animateThumbnail(true); } @@ -131,14 +131,14 @@ public class MagnificationThumbnail { * Hides thumbnail and removes the view from the window when finished animating. */ @AnyThread - public void hideThumbNail() { - mHandler.post(this::hideThumbNailMainThread); + public void hideThumbnail() { + mHandler.post(this::hideThumbnailMainThread); } @MainThread - private void hideThumbNailMainThread() { + private void hideThumbnailMainThread() { if (DEBUG) { - Log.d(LOG_TAG, "hideThumbNail " + mVisible); + Log.d(LOG_TAG, "hideThumbnail " + mVisible); } if (mVisible) { animateThumbnail(false); @@ -159,14 +159,14 @@ public class MagnificationThumbnail { + " fadeIn: " + fadeIn + " mVisible: " + mVisible + " isFadingIn: " + mIsFadingIn - + " isRunning: " + mThumbNailAnimator + + " isRunning: " + mThumbnailAnimator ); } // Reset countdown to hide automatically - mHandler.removeCallbacks(this::hideThumbNailMainThread); + mHandler.removeCallbacks(this::hideThumbnailMainThread); if (fadeIn) { - mHandler.postDelayed(this::hideThumbNailMainThread, LINGER_DURATION_MS); + mHandler.postDelayed(this::hideThumbnailMainThread, LINGER_DURATION_MS); } if (fadeIn == mIsFadingIn) { @@ -179,18 +179,18 @@ public class MagnificationThumbnail { mVisible = true; } - if (mThumbNailAnimator != null) { - mThumbNailAnimator.cancel(); + if (mThumbnailAnimator != null) { + mThumbnailAnimator.cancel(); } - mThumbNailAnimator = ObjectAnimator.ofFloat( + mThumbnailAnimator = ObjectAnimator.ofFloat( mThumbnailLayout, "alpha", fadeIn ? 1f : 0f ); - mThumbNailAnimator.setDuration( + mThumbnailAnimator.setDuration( fadeIn ? FADE_IN_ANIMATION_DURATION_MS : FADE_OUT_ANIMATION_DURATION_MS ); - mThumbNailAnimator.addListener(new Animator.AnimatorListener() { + mThumbnailAnimator.addListener(new Animator.AnimatorListener() { private boolean mIsCancelled; @Override @@ -235,7 +235,7 @@ public class MagnificationThumbnail { } }); - mThumbNailAnimator.start(); + mThumbnailAnimator.start(); } /** @@ -250,32 +250,32 @@ public class MagnificationThumbnail { * of the viewport, or {@link Float#NaN} to leave unchanged */ @AnyThread - public void updateThumbNail(float scale, float centerX, float centerY) { - mHandler.post(() -> updateThumbNailMainThread(scale, centerX, centerY)); + public void updateThumbnail(float scale, float centerX, float centerY) { + mHandler.post(() -> updateThumbnailMainThread(scale, centerX, centerY)); } @MainThread - private void updateThumbNailMainThread(float scale, float centerX, float centerY) { + private void updateThumbnailMainThread(float scale, float centerX, float centerY) { // Restart the fadeout countdown (or show if it's hidden) - showThumbNail(); + showThumbnail(); - var scaleDown = Float.isNaN(scale) ? mThumbNailView.getScaleX() : 1f / scale; + var scaleDown = Float.isNaN(scale) ? mThumbnailView.getScaleX() : 1f / scale; if (!Float.isNaN(scale)) { - mThumbNailView.setScaleX(scaleDown); - mThumbNailView.setScaleY(scaleDown); + mThumbnailView.setScaleX(scaleDown); + mThumbnailView.setScaleY(scaleDown); } float thumbnailWidth; float thumbnailHeight; - if (mThumbNailView.getWidth() == 0 || mThumbNailView.getHeight() == 0) { + if (mThumbnailView.getWidth() == 0 || mThumbnailView.getHeight() == 0) { // if the thumbnail view size is not updated correctly, we just use the cached values. thumbnailWidth = mThumbnailWidth; thumbnailHeight = mThumbnailHeight; } else { - thumbnailWidth = mThumbNailView.getWidth(); - thumbnailHeight = mThumbNailView.getHeight(); + thumbnailWidth = mThumbnailView.getWidth(); + thumbnailHeight = mThumbnailView.getHeight(); } if (!Float.isNaN(centerX)) { - var padding = mThumbNailView.getPaddingTop(); + var padding = mThumbnailView.getPaddingTop(); var ratio = 1f / BG_ASPECT_RATIO; var centerXScaled = centerX * ratio - (thumbnailWidth / 2f + padding); var centerYScaled = centerY * ratio - (thumbnailHeight / 2f + padding); @@ -283,15 +283,15 @@ public class MagnificationThumbnail { if (DEBUG) { Log.d( LOG_TAG, - "updateThumbNail centerXScaled : " + centerXScaled + "updateThumbnail centerXScaled : " + centerXScaled + " centerYScaled : " + centerYScaled - + " getTranslationX : " + mThumbNailView.getTranslationX() + + " getTranslationX : " + mThumbnailView.getTranslationX() + " ratio : " + ratio ); } - mThumbNailView.setTranslationX(centerXScaled); - mThumbNailView.setTranslationY(centerYScaled); + mThumbnailView.setTranslationX(centerXScaled); + mThumbnailView.setTranslationY(centerYScaled); } } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java index 35fc40cb60a69..a01c7bdd51444 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java @@ -200,7 +200,7 @@ public class FullScreenMagnificationControllerTest { assertFalse(mFullScreenMagnificationController.isRegistered(DISPLAY_0)); assertFalse(mFullScreenMagnificationController.isRegistered(DISPLAY_1)); - verify(mMockThumbnail, times(2)).hideThumbNail(); + verify(mMockThumbnail, times(2)).hideThumbnail(); } @Test @@ -540,7 +540,7 @@ public class FullScreenMagnificationControllerTest { // The first time is triggered when the thumbnail is just created. // The second time is triggered when the magnification region changed. - verify(mMockThumbnail, times(2)).setThumbNailBounds( + verify(mMockThumbnail, times(2)).setThumbnailBounds( any(), anyFloat(), anyFloat(), anyFloat()); } @@ -912,7 +912,7 @@ public class FullScreenMagnificationControllerTest { verifyNoMoreInteractions(mMockWindowManager); verify(mMockThumbnail) - .updateThumbNail(eq(scale), eq(startCenter.x), eq(startCenter.y)); + .updateThumbnail(eq(scale), eq(startCenter.x), eq(startCenter.y)); } @Test diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationThumbnailTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationThumbnailTest.java index 60c8148180da4..3baa102b882b4 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationThumbnailTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationThumbnailTest.java @@ -66,14 +66,14 @@ public class MagnificationThumbnailTest { @Test public void updateThumbnailShows() { - runOnMainSync(() -> mMagnificationThumbnail.updateThumbNail( + runOnMainSync(() -> mMagnificationThumbnail.updateThumbnail( /* scale= */ 2f, /* centerX= */ 5, /* centerY= */ 10 )); idle(); - runOnMainSync(() -> mMagnificationThumbnail.updateThumbNail( + runOnMainSync(() -> mMagnificationThumbnail.updateThumbnail( /* scale= */ 2.2f, /* centerX= */ 15, /* centerY= */ 50 @@ -86,7 +86,7 @@ public class MagnificationThumbnailTest { @Test public void updateThumbnailLingersThenHidesAfterTimeout() throws InterruptedException { - runOnMainSync(() -> mMagnificationThumbnail.updateThumbNail( + runOnMainSync(() -> mMagnificationThumbnail.updateThumbnail( /* scale= */ 2f, /* centerX= */ 5, /* centerY= */ 10 @@ -103,14 +103,14 @@ public class MagnificationThumbnailTest { @Test public void hideThumbnailRemoves() throws InterruptedException { - runOnMainSync(() -> mMagnificationThumbnail.updateThumbNail( + runOnMainSync(() -> mMagnificationThumbnail.updateThumbnail( /* scale= */ 2f, /* centerX= */ 5, /* centerY= */ 10 )); idle(); - runOnMainSync(() -> mMagnificationThumbnail.hideThumbNail()); + runOnMainSync(() -> mMagnificationThumbnail.hideThumbnail()); idle(); // Wait for the fade out animation @@ -122,10 +122,10 @@ public class MagnificationThumbnailTest { @Test public void hideShowHideShowHideRemoves() throws InterruptedException { - runOnMainSync(() -> mMagnificationThumbnail.hideThumbNail()); + runOnMainSync(() -> mMagnificationThumbnail.hideThumbnail()); idle(); - runOnMainSync(() -> mMagnificationThumbnail.updateThumbNail( + runOnMainSync(() -> mMagnificationThumbnail.updateThumbnail( /* scale= */ 2f, /* centerX= */ 5, /* centerY= */ 10 @@ -135,17 +135,17 @@ public class MagnificationThumbnailTest { // Wait for the fade in animation Thread.sleep(200L); - runOnMainSync(() -> mMagnificationThumbnail.hideThumbNail()); + runOnMainSync(() -> mMagnificationThumbnail.hideThumbnail()); idle(); - runOnMainSync(() -> mMagnificationThumbnail.updateThumbNail( + runOnMainSync(() -> mMagnificationThumbnail.updateThumbnail( /* scale= */ 2f, /* centerX= */ 5, /* centerY= */ 10 )); idle(); - runOnMainSync(() -> mMagnificationThumbnail.hideThumbNail()); + runOnMainSync(() -> mMagnificationThumbnail.hideThumbnail()); idle(); @@ -158,7 +158,7 @@ public class MagnificationThumbnailTest { @Test public void hideWithoutShowDoesNothing() throws InterruptedException { - runOnMainSync(() -> mMagnificationThumbnail.hideThumbNail()); + runOnMainSync(() -> mMagnificationThumbnail.hideThumbnail()); idle(); // Wait for the fade out animation @@ -172,7 +172,7 @@ public class MagnificationThumbnailTest { @Test public void whenHidden_setBoundsDoesNotShow() throws InterruptedException { - runOnMainSync(() -> mMagnificationThumbnail.setThumbNailBounds( + runOnMainSync(() -> mMagnificationThumbnail.setThumbnailBounds( new Rect(), /* scale= */ 2f, /* centerX= */ 5,