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

Commit b23e8bc3 authored by Minche Li's avatar Minche Li Committed by Android (Google) Code Review
Browse files

Merge changes from topic "magnification_switch" into sc-dev

* changes:
  Makes the movable region of magnification button sticking to the edges
  Makes magnification switch UI never overlap navigationBar and statusBar
parents e74cc356 778e94a7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1293,7 +1293,7 @@
    <dimen name="magnification_drag_view_size">36dp</dimen>
    <dimen name="magnification_controls_size">90dp</dimen>
    <dimen name="magnification_switch_button_size">48dp</dimen>
    <dimen name="magnification_switch_button_padding">6dp</dimen>
    <dimen name="magnification_switch_button_margin">16dp</dimen>
    <dimen name="magnifier_left_right_controls_width">35dp</dimen>
    <dimen name="magnifier_left_right_controls_height">45dp</dimen>
    <dimen name="magnifier_up_down_controls_width">45dp</dimen>
+111 −27
Original line number Diff line number Diff line
@@ -22,14 +22,17 @@ import android.annotation.NonNull;
import android.annotation.UiContext;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.MathUtils;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityManager;
@@ -38,6 +41,7 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.ImageView;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.R;

import java.util.Collections;
@@ -45,8 +49,8 @@ import java.util.Collections;
/**
 * Shows/hides a {@link android.widget.ImageView} on the screen and changes the values of
 * {@link Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE} when the UI is toggled.
 * The button icon is movable by dragging. And the button UI would automatically be dismissed after
 * displaying for a period of time.
 * The button icon is movable by dragging and it would not overlap navigation bar window.
 * And the button UI would automatically be dismissed after displaying for a period of time.
 */
class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureListener {

@@ -64,25 +68,30 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
    private final AccessibilityManager mAccessibilityManager;
    private final WindowManager mWindowManager;
    private final ImageView mImageView;
    private final Runnable mWindowInsetChangeRunnable;
    private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
    private int mMagnificationMode = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
    private final LayoutParams mParams;
    @VisibleForTesting
    final Rect mDraggableWindowBounds = new Rect();
    private boolean mIsVisible = false;
    private final MagnificationGestureDetector mGestureDetector;
    private boolean mSingleTapDetected = false;
    private boolean mToLeftScreenEdge = false;

    MagnificationModeSwitch(@UiContext Context context) {
        this(context, createView(context));
        this(context, createView(context), new SfVsyncFrameCallbackProvider());
    }

    @VisibleForTesting
    MagnificationModeSwitch(Context context, @NonNull ImageView imageView) {
    MagnificationModeSwitch(Context context, @NonNull ImageView imageView,
            SfVsyncFrameCallbackProvider sfVsyncFrameProvider) {
        mContext = context;
        mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
        mWindowManager = (WindowManager) mContext.getSystemService(
                Context.WINDOW_SERVICE);
        mWindowManager = mContext.getSystemService(WindowManager.class);
        mSfVsyncFrameProvider = sfVsyncFrameProvider;
        mParams = createLayoutParams(context);
        mImageView = imageView;
        applyResourcesValues();
        mImageView.setOnTouchListener(this::onTouch);
        mImageView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
            @Override
@@ -107,6 +116,15 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
                return super.performAccessibilityAction(host, action, args);
            }
        });
        mWindowInsetChangeRunnable = this::onWindowInsetChanged;
        mImageView.setOnApplyWindowInsetsListener((v, insets) -> {
            // Adds a pending post check to avoiding redundant calculation because this callback
            // is sent frequently when the switch icon window dragged by the users.
            if (!mImageView.getHandler().hasCallbacks(mWindowInsetChangeRunnable)) {
                mImageView.getHandler().post(mWindowInsetChangeRunnable);
            }
            return v.onApplyWindowInsets(insets);
        });

        mFadeInAnimationTask = () -> {
            mImageView.animate()
@@ -133,11 +151,17 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
        return mContext.getResources().getString(stringId);
    }

    private void applyResourcesValues() {
        final int padding = mContext.getResources().getDimensionPixelSize(
                R.dimen.magnification_switch_button_padding);
        mImageView.setPadding(padding, padding, padding, padding);
        mImageView.setImageResource(getIconResId(mMagnificationMode));
    private void applyResourcesValuesWithDensityChanged() {
        final int size = mContext.getResources().getDimensionPixelSize(
                R.dimen.magnification_switch_button_size);
        mParams.height = size;
        mParams.width = size;
        if (mIsVisible) {
            stickToScreenEdge(mToLeftScreenEdge);
            // Reset button to make its window layer always above the mirror window.
            removeButton();
            showButton(mMagnificationMode, /* resetPosition= */false);
        }
    }

    private boolean onTouch(View v, MotionEvent event) {
@@ -168,6 +192,12 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL

    @Override
    public boolean onFinish(float xOffset, float yOffset) {
        if (mIsVisible) {
            final int windowWidth = mWindowManager.getCurrentWindowMetrics().getBounds().width();
            final int halfWindowWidth = windowWidth / 2;
            mToLeftScreenEdge = (mParams.x < halfWindowWidth);
            stickToScreenEdge(mToLeftScreenEdge);
        }
        if (!mSingleTapDetected) {
            showButton(mMagnificationMode);
        }
@@ -175,10 +205,18 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
        return true;
    }

    private void stickToScreenEdge(boolean toLeftScreenEdge) {
        mParams.x = toLeftScreenEdge
                ? mDraggableWindowBounds.left : mDraggableWindowBounds.right;
        updateButtonViewLayoutIfNeeded();
    }

    private void moveButton(float offsetX, float offsetY) {
        mParams.x -= offsetX;
        mParams.y -= offsetY;
        mWindowManager.updateViewLayout(mImageView, mParams);
        mSfVsyncFrameProvider.postFrameCallback(l -> {
            mParams.x += offsetX;
            mParams.y += offsetY;
            updateButtonViewLayoutIfNeeded();
        });
    }

    void removeButton() {
@@ -193,16 +231,32 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
        mImageView.setAlpha(0f);
        mWindowManager.removeView(mImageView);
        mIsVisible = false;
        mParams.x = 0;
        mParams.y = 0;
    }

    void showButton(int mode) {
        showButton(mode, true);
    }

    /**
     * Shows magnification switch button for the specified magnification mode.
     * When the button is going to be visible by calling this method, the layout position can be
     * reset depending on the flag.
     *
     * @param mode          The magnification mode
     * @param resetPosition if the button position needs be reset
     */
    private void showButton(int mode, boolean resetPosition) {
        if (mMagnificationMode != mode) {
            mMagnificationMode = mode;
            mImageView.setImageResource(getIconResId(mode));
        }
        if (!mIsVisible) {
            if (resetPosition) {
                mDraggableWindowBounds.set(getDraggableWindowBounds());
                mParams.x = mDraggableWindowBounds.right;
                mParams.y = mDraggableWindowBounds.bottom;
                mToLeftScreenEdge = false;
            }
            mWindowManager.addView(mImageView, mParams);
            // Exclude magnification switch button from system gesture area.
            setSystemGestureExclusion();
@@ -229,12 +283,7 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL

    void onConfigurationChanged(int configDiff) {
        if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
            applyResourcesValues();
            if (mIsVisible) {
                mWindowManager.updateViewLayout(mImageView, mParams);
                // Exclude magnification switch button from system gesture area.
                setSystemGestureExclusion();
            }
            applyResourcesValuesWithDensityChanged();
            return;
        }
        if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) {
@@ -243,6 +292,25 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
        }
    }

    private void onWindowInsetChanged() {
        final Rect newBounds = getDraggableWindowBounds();
        if (mDraggableWindowBounds.equals(newBounds)) {
            return;
        }
        mDraggableWindowBounds.set(newBounds);
        stickToScreenEdge(mToLeftScreenEdge);
    }

    private void updateButtonViewLayoutIfNeeded() {
        if (mIsVisible) {
            mParams.x = MathUtils.constrain(mParams.x, mDraggableWindowBounds.left,
                    mDraggableWindowBounds.right);
            mParams.y = MathUtils.constrain(mParams.y, mDraggableWindowBounds.top,
                    mDraggableWindowBounds.bottom);
            mWindowManager.updateViewLayout(mImageView, mParams);
        }
    }

    private void updateAccessibilityWindowTitle() {
        mParams.accessibilityTitle = getAccessibilityWindowTitle(mContext);
        if (mIsVisible) {
@@ -283,17 +351,34 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
    }

    private static LayoutParams createLayoutParams(Context context) {
        final int size = context.getResources().getDimensionPixelSize(
                R.dimen.magnification_switch_button_size);
        final LayoutParams params = new LayoutParams(
                LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT,
                size,
                size,
                LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY,
                LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSPARENT);
        params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
        params.gravity = Gravity.TOP | Gravity.LEFT;
        params.accessibilityTitle = getAccessibilityWindowTitle(context);
        return params;
    }

    private Rect getDraggableWindowBounds() {
        final int layoutMargin = mContext.getResources().getDimensionPixelSize(
                R.dimen.magnification_switch_button_margin);
        final Rect boundRect = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
        final Insets systemBars =
                mWindowManager.getCurrentWindowMetrics().getWindowInsets()
                        .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars());
        final Rect insets = new Rect(layoutMargin,
                systemBars.top + layoutMargin,
                mParams.width + layoutMargin,
                mParams.height + layoutMargin + systemBars.bottom);
        boundRect.inset(insets);
        return boundRect;
    }

    private static String getAccessibilityWindowTitle(Context context) {
        return context.getString(com.android.internal.R.string.android_system_label);
    }
@@ -305,5 +390,4 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
                            new Rect(0, 0, mImageView.getWidth(), mImageView.getHeight())));
        });
    }

}
+105 −20
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.WindowInsets.Type.systemBars;
import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK;

import static com.android.systemui.accessibility.MagnificationModeSwitch.DEFAULT_FADE_OUT_ANIMATION_DELAY_MS;
@@ -33,6 +34,7 @@ import static junit.framework.Assert.assertNotNull;

import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -41,19 +43,27 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Choreographer;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewPropertyAnimator;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -61,6 +71,7 @@ import android.widget.ImageView;

import androidx.test.filters.SmallTest;

import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;

@@ -69,6 +80,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@@ -77,6 +89,7 @@ import java.util.List;

@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class MagnificationModeSwitchTest extends SysuiTestCase {

    private static final float FADE_IN_ALPHA = 1f;
@@ -86,7 +99,10 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
    @Mock
    private AccessibilityManager mAccessibilityManager;
    @Mock
    private WindowManager mWindowManager;
    private SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
    @Mock
    private Handler mHandler;
    private TestableWindowManager mWindowManager;
    private ViewPropertyAnimator mViewPropertyAnimator;
    private MagnificationModeSwitch mMagnificationModeSwitch;
    private View.OnTouchListener mTouchListener;
@@ -96,10 +112,8 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        WindowManager wm = mContext.getSystemService(WindowManager.class);
        doAnswer(invocation ->
                wm.getMaximumWindowMetrics()
        ).when(mWindowManager).getMaximumWindowMetrics();
        final WindowManager wm = mContext.getSystemService(WindowManager.class);
        mWindowManager = spy(new TestableWindowManager(wm));
        mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
        mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager);
        mSpyImageView = Mockito.spy(new ImageView(mContext));
@@ -110,7 +124,14 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
            return null;
        }).when(mSpyImageView).setOnTouchListener(
                any(View.OnTouchListener.class));
        mMagnificationModeSwitch = new MagnificationModeSwitch(mContext, mSpyImageView);
        doAnswer(invocation -> {
            Choreographer.FrameCallback callback = invocation.getArgument(0);
            callback.doFrame(0);
            return null;
        }).when(mSfVsyncFrameProvider).postFrameCallback(
                any(Choreographer.FrameCallback.class));
        mMagnificationModeSwitch = new MagnificationModeSwitch(mContext, mSpyImageView,
                mSfVsyncFrameProvider);
        assertNotNull(mTouchListener);
    }

@@ -178,19 +199,64 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
    }

    @Test
    public void onConfigurationChanged_buttonIsShowing_updateResourcesAndLayout() {
    public void onDensityChanged_buttonIsShowing_updateResourcesAndLayout() {
        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
        resetAndStubMockImageViewAndAnimator();

        mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);

        verify(mSpyImageView).setPadding(anyInt(), anyInt(), anyInt(), anyInt());
        verify(mSpyImageView).setImageResource(
                getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN));
        verify(mWindowManager).updateViewLayout(eq(mSpyImageView), any());
        InOrder inOrder = Mockito.inOrder(mWindowManager);
        inOrder.verify(mWindowManager).updateViewLayout(eq(mSpyImageView), any());
        inOrder.verify(mWindowManager).removeView(eq(mSpyImageView));
        inOrder.verify(mWindowManager).addView(eq(mSpyImageView), any());
        verify(mSpyImageView).setSystemGestureExclusionRects(any(List.class));
    }

    @Test
    public void onApplyWindowInsetsWithBoundsChange_buttonIsShowing_updateLayoutPosition() {
        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);

        mMagnificationModeSwitch.mDraggableWindowBounds.inset(10, 10);
        mSpyImageView.onApplyWindowInsets(WindowInsets.CONSUMED);

        verify(mWindowManager).updateViewLayout(eq(mSpyImageView),
                any(WindowManager.LayoutParams.class));
        assertLayoutPosition(/* toLeftScreenEdge= */ false);
    }

    @Test
    public void onApplyWindowInsetsWithWindowInsetsChange_buttonIsShowing_draggableBoundsChanged() {
        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
        final Rect oldDraggableBounds = new Rect(mMagnificationModeSwitch.mDraggableWindowBounds);

        mWindowManager.setWindowInsets(new WindowInsets.Builder()
                .setInsetsIgnoringVisibility(systemBars(), Insets.of(0, 20, 0, 20))
                .build());
        mSpyImageView.onApplyWindowInsets(WindowInsets.CONSUMED);

        assertNotEquals(oldDraggableBounds, mMagnificationModeSwitch.mDraggableWindowBounds);
    }

    @Test
    public void onDraggingGestureFinish_buttonIsShowing_stickToRightEdge() {
        final int windowHalfWidth =
                mWindowManager.getCurrentWindowMetrics().getBounds().width() / 2;
        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);

        // Drag button to right side on screen
        final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop() + 10;
        final long downTime = SystemClock.uptimeMillis();
        mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
                downTime, 0, ACTION_DOWN, 100, 100));
        mTouchListener.onTouch(mSpyImageView,
                obtainMotionEvent(downTime, downTime, ACTION_MOVE, windowHalfWidth - offset, 100));

        mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
                downTime, downTime, ACTION_UP, windowHalfWidth - offset, 100));

        assertLayoutPosition(/* toLeftScreenEdge= */false);
    }

    @Test
    public void performSingleTap_fullscreenMode_removeViewAndChangeSettingsValue() {
        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
@@ -344,12 +410,12 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
    public void showButton_hasAccessibilityWindowTitle() {
        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);

        ArgumentCaptor<WindowManager.LayoutParams> paramsArgumentCaptor = ArgumentCaptor.forClass(
                WindowManager.LayoutParams.class);
        verify(mWindowManager).addView(eq(mSpyImageView), paramsArgumentCaptor.capture());
        final WindowManager.LayoutParams layoutPrams =
                mWindowManager.getLayoutParamsFromAttachedView();
        assertNotNull(layoutPrams);
        assertEquals(getContext().getResources().getString(
                com.android.internal.R.string.android_system_label),
                paramsArgumentCaptor.getValue().accessibilityTitle);
                layoutPrams.accessibilityTitle);
    }

    @Test
@@ -361,10 +427,10 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
                com.android.internal.R.string.android_system_label, newA11yWindowTitle);
        mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_LOCALE);

        ArgumentCaptor<WindowManager.LayoutParams> paramsArgumentCaptor = ArgumentCaptor.forClass(
                WindowManager.LayoutParams.class);
        verify(mWindowManager).updateViewLayout(eq(mSpyImageView), paramsArgumentCaptor.capture());
        assertEquals(newA11yWindowTitle, paramsArgumentCaptor.getValue().accessibilityTitle);
        final WindowManager.LayoutParams layoutParams =
                mWindowManager.getLayoutParamsFromAttachedView();
        assertNotNull(layoutParams);
        assertEquals(newA11yWindowTitle, layoutParams.accessibilityTitle);
    }

    private void assertModeUnchanged(int expectedMode) {
@@ -374,7 +440,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
    }

    private void assertShowFadingAnimation(float alpha) {
        ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
        final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
        if (alpha == FADE_IN_ALPHA) { // Fade-in
            verify(mSpyImageView).postOnAnimation(runnableCaptor.capture());
        } else { // Fade-out
@@ -392,6 +458,13 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
    private void resetAndStubMockImageViewAndAnimator() {
        resetAndStubMockAnimator();
        Mockito.reset(mSpyImageView);
        final Handler handler = mock(Handler.class);
        when(mSpyImageView.getHandler()).thenReturn(handler);
        doAnswer(invocation -> {
            final Runnable runnable = invocation.getArgument(0);
            runnable.run();
            return null;
        }).when(handler).post(any(Runnable.class));
        doAnswer(invocation -> {
            final Runnable runnable = invocation.getArgument(0);
            runnable.run();
@@ -440,4 +513,16 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
        mFadeOutAnimation.run();
        mFadeOutAnimation = null;
    }

    private void assertLayoutPosition(boolean toLeftScreenEdge) {
        final int expectedX =
                toLeftScreenEdge ? mMagnificationModeSwitch.mDraggableWindowBounds.left
                        : mMagnificationModeSwitch.mDraggableWindowBounds.right;
        final int expectedY = mMagnificationModeSwitch.mDraggableWindowBounds.bottom;
        final WindowManager.LayoutParams layoutParams =
                mWindowManager.getLayoutParamsFromAttachedView();
        assertNotNull(layoutParams);
        assertEquals(expectedX, layoutParams.x);
        assertEquals(expectedY, layoutParams.y);
    }
}
+109 −0

File added.

Preview size limit exceeded, changes collapsed.

+28 −94

File changed.

Preview size limit exceeded, changes collapsed.