Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ff29df4 authored by Roy Chou's avatar Roy Chou Committed by Automerger Merge Worker
Browse files

Merge changes Iaf1ecb67,Ifdc84b17,I1480b734,I2857cd33 into udc-dev am: 03081ace

parents f512697f 03081ace
Loading
Loading
Loading
Loading
+10 −55
Original line number Diff line number Diff line
@@ -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;
    }
}
+71 −33
Original line number Diff line number Diff line
@@ -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 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() {
        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);
        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();
        }
    }

    /**
+4 −2
Original line number Diff line number Diff line
@@ -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(
+115 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}
+53 −39
Original line number Diff line number Diff line
@@ -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);
        }
    }

Loading