Merge changes Iaf1ecb67,Ifdc84b17,I1480b734,I2857cd33 into udc-dev
* changes: chore(#MagnificationThumbnail): rename thumbNail to thumbnail fix(#MagnificationThumbnail): thumbnail magnifying area position is not correct sometimes chore(#MagnificationThumbnail): add feature flag file and fix size not correct sometimes chore(#Magnification): add MagnificationFeatureFlagBase
This commit is contained in:
@@ -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.
|
||||
*
|
||||
* <p>{@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.
|
||||
*
|
||||
* <p>{@see DeviceConfig#addOnPropertiesChangedListener(String, Executor,
|
||||
* DeviceConfig.OnPropertiesChangedListener)}
|
||||
*/
|
||||
public static void removeOnChangedListener(
|
||||
@NonNull DeviceConfig.OnPropertiesChangedListener onChangedListener) {
|
||||
DeviceConfig.removeOnPropertiesChangedListener(onChangedListener);
|
||||
@Override
|
||||
boolean getDefaultValue() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<MagnificationThumbnail> 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,16 +595,16 @@ 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);
|
||||
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(
|
||||
mMagnificationThumbnail.setThumbnailBounds(
|
||||
mMagnificationBounds,
|
||||
scale,
|
||||
centerX,
|
||||
@@ -615,20 +614,38 @@ public class FullScreenMagnificationController implements
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
void hideThumbNail() {
|
||||
void hideThumbnail() {
|
||||
if (mMagnificationThumbnail != null) {
|
||||
mMagnificationThumbnail.hideThumbNail();
|
||||
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<MagnificationThumbnail> thumbnailSupplier) {
|
||||
Supplier<MagnificationThumbnail> 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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -93,6 +93,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
|
||||
private final SparseArray<DisableMagnificationCallback>
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -710,7 +712,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
|
||||
}
|
||||
|
||||
public boolean isAlwaysOnMagnificationFeatureFlagEnabled() {
|
||||
return AlwaysOnMagnificationFeatureFlag.isAlwaysOnMagnificationEnabled();
|
||||
return mAlwaysOnMagnificationFeatureFlag.isFeatureFlagEnabled();
|
||||
}
|
||||
|
||||
private DisableMagnificationCallback getDisableMagnificationEndRunnableLocked(
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* <p>{@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.
|
||||
*
|
||||
* <p>{@see DeviceConfig#addOnPropertiesChangedListener(String, Executor,
|
||||
* DeviceConfig.OnPropertiesChangedListener)}
|
||||
*/
|
||||
public void removeOnChangedListener(
|
||||
@NonNull DeviceConfig.OnPropertiesChangedListener onChangedListener) {
|
||||
DeviceConfig.removeOnPropertiesChangedListener(onChangedListener);
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,9 @@ public class MagnificationThumbnail {
|
||||
@VisibleForTesting
|
||||
public final FrameLayout mThumbnailLayout;
|
||||
|
||||
private final View mThumbNailView;
|
||||
private final View mThumbnailView;
|
||||
private int mThumbnailWidth;
|
||||
private int mThumbnailHeight;
|
||||
|
||||
private final WindowManager.LayoutParams mBackgroundParams;
|
||||
private boolean mVisible = false;
|
||||
@@ -66,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;
|
||||
|
||||
/**
|
||||
@@ -79,9 +81,11 @@ 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;
|
||||
mThumbnailHeight = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,35 +94,35 @@ 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private void showThumbNail() {
|
||||
private void showThumbnail() {
|
||||
if (DEBUG) {
|
||||
Log.d(LOG_TAG, "showThumbNail " + mVisible);
|
||||
Log.d(LOG_TAG, "showThumbnail " + mVisible);
|
||||
}
|
||||
animateThumbnail(true);
|
||||
}
|
||||
@@ -127,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);
|
||||
@@ -155,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) {
|
||||
@@ -175,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
|
||||
@@ -231,7 +235,7 @@ public class MagnificationThumbnail {
|
||||
}
|
||||
});
|
||||
|
||||
mThumbNailAnimator.start();
|
||||
mThumbnailAnimator.start();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,38 +250,48 @@ 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 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 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(
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -909,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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user