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

Commit 732aed15 authored by mincheli's avatar mincheli
Browse files

Makes magnification switch UI never overlap navigationBar and statusBar

This change contrains the x,y postion of switch button to make
the button never overlap navigation bar window and status bar window.
When the orientation is changed or navigation mode is change, the
position of switch button should be ajusted by the draggable bounds
because the window insets are updated.

Bug: 185288922
Test: atest MagnificationModeSwitchTest; atest ModeSwitchesControllerTest;
Change-Id: Idc03275f39418c18a190cdff6ffb0e94280c6281
parent 1d2868c4
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>
+96 −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,29 @@ 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;

    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 +115,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 +150,16 @@ 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) {
            mWindowManager.updateViewLayout(mImageView, mParams);
            // Exclude magnification switch button from system gesture area.
            setSystemGestureExclusion();
        }
    }

    private boolean onTouch(View v, MotionEvent event) {
@@ -176,9 +198,11 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
    }

    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 +217,31 @@ 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;
            }
            mWindowManager.addView(mImageView, mParams);
            // Exclude magnification switch button from system gesture area.
            setSystemGestureExclusion();
@@ -229,12 +268,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 +277,25 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
        }
    }

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

    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 +336,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 +375,4 @@ class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureL
                            new Rect(0, 0, mImageView.getWidth(), mImageView.getHeight())));
        });
    }

}
+77 −18
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;

@@ -77,6 +88,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 +98,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 +111,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 +123,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 +198,41 @@ 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());
        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();
    }

    @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 performSingleTap_fullscreenMode_removeViewAndChangeSettingsValue() {
        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
@@ -344,12 +386,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 +403,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) {
@@ -392,6 +434,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 +489,14 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
        mFadeOutAnimation.run();
        mFadeOutAnimation = null;
    }

    private void assertLayoutPosition() {
        final int expectedX = 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
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.accessibility;

import static android.view.WindowInsets.Type.systemGestures;

import android.graphics.Insets;
import android.graphics.Region;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;

public class TestableWindowManager implements WindowManager {

    private final WindowManager mWindowManager;
    private View mView;
    private WindowInsets mWindowInsets = null;

    TestableWindowManager(WindowManager windowManager) {
        mWindowManager = windowManager;
    }

    @Override
    public Display getDefaultDisplay() {
        return mWindowManager.getDefaultDisplay();
    }

    @Override
    public void removeViewImmediate(View view) {
        mWindowManager.removeViewImmediate(view);
    }

    @Override
    public void requestAppKeyboardShortcuts(WindowManager.KeyboardShortcutsReceiver receiver,
            int deviceId) {
        mWindowManager.requestAppKeyboardShortcuts(receiver, deviceId);
    }

    @Override
    public Region getCurrentImeTouchRegion() {
        return mWindowManager.getCurrentImeTouchRegion();
    }

    @Override
    public void addView(View view, ViewGroup.LayoutParams params) {
        mView = view;
        mWindowManager.addView(view, params);
    }

    @Override
    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
        mWindowManager.updateViewLayout(view, params);
    }

    @Override
    public void removeView(View view) {
        mView = null;
        mWindowManager.removeView(view);
    }

    @Override
    public WindowMetrics getCurrentWindowMetrics() {
        final Insets systemGesturesInsets = Insets.of(0, 0, 0, 10);
        final WindowInsets insets = new WindowInsets.Builder()
                .setInsets(systemGestures(), systemGesturesInsets)
                .build();
        final WindowMetrics windowMetrics = new WindowMetrics(
                mWindowManager.getCurrentWindowMetrics().getBounds(),
                mWindowInsets == null ? insets : mWindowInsets);
        return windowMetrics;
    }

    @Override
    public WindowMetrics getMaximumWindowMetrics() {
        return mWindowManager.getMaximumWindowMetrics();
    }

    public View getAttachedView() {
        return mView;
    }

    public WindowManager.LayoutParams getLayoutParamsFromAttachedView() {
        if (mView == null) {
            return null;
        }
        return (WindowManager.LayoutParams) mView.getLayoutParams();
    }

    public void setWindowInsets(WindowInsets insets) {
        mWindowInsets = insets;
    }
}
+28 −94

File changed.

Preview size limit exceeded, changes collapsed.