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

Commit a7aa6dce authored by Winson Chung's avatar Winson Chung Committed by Android (Google) Code Review
Browse files

Merge "Update size compat restart button surface position after display insests changed"

parents 4fbb0a84 e048e696
Loading
Loading
Loading
Loading
+73 −1
Original line number Diff line number Diff line
@@ -24,11 +24,16 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
import android.view.InsetsSourceControl;
import android.view.InsetsState;

import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayController.OnDisplaysChangedListener;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;

@@ -42,7 +47,7 @@ import java.util.function.Consumer;
 * Controls to show/update restart-activity buttons on Tasks based on whether the foreground
 * activities are in size compatibility mode.
 */
public class SizeCompatUIController implements DisplayController.OnDisplaysChangedListener,
public class SizeCompatUIController implements OnDisplaysChangedListener,
        DisplayImeController.ImePositionProcessor {

    /** Callback for size compat UI interaction. */
@@ -58,6 +63,10 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
    /** Whether the IME is shown on display id. */
    private final Set<Integer> mDisplaysWithIme = new ArraySet<>(1);

    /** {@link PerDisplayOnInsetsChangedListener} by display id. */
    private final SparseArray<PerDisplayOnInsetsChangedListener> mOnInsetsChangedListeners =
            new SparseArray<>(0);

    /** The showing UIs by task id. */
    private final SparseArray<SizeCompatUILayout> mActiveLayouts = new SparseArray<>(0);

@@ -66,6 +75,7 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang

    private final Context mContext;
    private final DisplayController mDisplayController;
    private final DisplayInsetsController mDisplayInsetsController;
    private final DisplayImeController mImeController;
    private final SyncTransactionQueue mSyncQueue;

@@ -76,10 +86,12 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang

    public SizeCompatUIController(Context context,
            DisplayController displayController,
            DisplayInsetsController displayInsetsController,
            DisplayImeController imeController,
            SyncTransactionQueue syncQueue) {
        mContext = context;
        mDisplayController = displayController;
        mDisplayInsetsController = displayInsetsController;
        mImeController = imeController;
        mSyncQueue = syncQueue;
        mDisplayController.addDisplayWindowListener(this);
@@ -114,9 +126,15 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
        }
    }

    @Override
    public void onDisplayAdded(int displayId) {
        addOnInsetsChangedListener(displayId);
    }

    @Override
    public void onDisplayRemoved(int displayId) {
        mDisplayContextCache.remove(displayId);
        removeOnInsetsChangedListener(displayId);

        // Remove all size compat UIs on the removed display.
        final List<Integer> toRemoveTaskIds = new ArrayList<>();
@@ -126,8 +144,29 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
        }
    }

    private void addOnInsetsChangedListener(int displayId) {
        PerDisplayOnInsetsChangedListener listener = new PerDisplayOnInsetsChangedListener(
                displayId);
        listener.register();
        mOnInsetsChangedListeners.put(displayId, listener);
    }

    private void removeOnInsetsChangedListener(int displayId) {
        PerDisplayOnInsetsChangedListener listener = mOnInsetsChangedListeners.get(displayId);
        if (listener == null) {
            return;
        }
        listener.unregister();
        mOnInsetsChangedListeners.remove(displayId);
    }


    @Override
    public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
        updateDisplayLayout(displayId);
    }

    private void updateDisplayLayout(int displayId) {
        final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(displayId);
        forAllLayoutsOnDisplay(displayId, layout -> layout.updateDisplayLayout(displayLayout));
    }
@@ -219,4 +258,37 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
            }
        }
    }

    /** An implementation of {@link OnInsetsChangedListener} for a given display id. */
    private class PerDisplayOnInsetsChangedListener implements OnInsetsChangedListener {
        final int mDisplayId;
        final InsetsState mInsetsState = new InsetsState();

        PerDisplayOnInsetsChangedListener(int displayId) {
            mDisplayId = displayId;
        }

        void register() {
            mDisplayInsetsController.addInsetsChangedListener(mDisplayId, this);
        }

        void unregister() {
            mDisplayInsetsController.removeInsetsChangedListener(mDisplayId, this);
        }

        @Override
        public void insetsChanged(InsetsState insetsState) {
            if (mInsetsState.equals(insetsState)) {
                return;
            }
            mInsetsState.set(insetsState);
            updateDisplayLayout(mDisplayId);
        }

        @Override
        public void insetsControlChanged(InsetsState insetsState,
                InsetsSourceControl[] activeControls) {
            insetsChanged(insetsState);
        }
    }
}
+14 −10
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ class SizeCompatUILayout {
    private final int mTaskId;
    private ShellTaskOrganizer.TaskListener mTaskListener;
    private DisplayLayout mDisplayLayout;
    private final Rect mStableBounds;
    private final int mButtonWidth;
    private final int mButtonHeight;
    private final int mPopupOffsetX;
@@ -89,6 +90,9 @@ class SizeCompatUILayout {
        mShouldShowHint = !hasShownHint;
        mButtonWindowManager = new SizeCompatUIWindowManager(mContext, taskConfig, this);

        mStableBounds = new Rect();
        mDisplayLayout.getStableBounds(mStableBounds);

        final Resources resources = mContext.getResources();
        mButtonWidth = resources.getDimensionPixelSize(R.dimen.size_compat_button_width);
        mButtonHeight = resources.getDimensionPixelSize(R.dimen.size_compat_button_height);
@@ -173,8 +177,7 @@ class SizeCompatUILayout {
        if (!taskConfig.windowConfiguration.getBounds()
                .equals(prevTaskConfig.windowConfiguration.getBounds())) {
            // Reposition the UI surfaces.
            updateButtonSurfacePosition();
            updateHintSurfacePosition();
            updateAllSurfacePositions();
        }

        if (taskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection()) {
@@ -190,19 +193,14 @@ class SizeCompatUILayout {

    /** Called when display layout changed. */
    void updateDisplayLayout(DisplayLayout displayLayout) {
        if (displayLayout == mDisplayLayout) {
            return;
        }

        final Rect prevStableBounds = new Rect();
        final Rect prevStableBounds = mStableBounds;
        final Rect curStableBounds = new Rect();
        mDisplayLayout.getStableBounds(prevStableBounds);
        displayLayout.getStableBounds(curStableBounds);
        mDisplayLayout = displayLayout;
        if (!prevStableBounds.equals(curStableBounds)) {
            // Stable bounds changed, update UI surface positions.
            updateButtonSurfacePosition();
            updateHintSurfacePosition();
            updateAllSurfacePositions();
            mStableBounds.set(curStableBounds);
        }
    }

@@ -268,6 +266,11 @@ class SizeCompatUILayout {
        createSizeCompatHint();
    }

    private void updateAllSurfacePositions() {
        updateButtonSurfacePosition();
        updateHintSurfacePosition();
    }

    @VisibleForTesting
    void updateButtonSurfacePosition() {
        if (mButton == null || mButtonWindowManager.getSurfaceControl() == null) {
@@ -290,6 +293,7 @@ class SizeCompatUILayout {
        updateSurfacePosition(leash, positionX, positionY);
    }

    @VisibleForTesting
    void updateHintSurfacePosition() {
        if (mHint == null || mHintWindowManager == null
                || mHintWindowManager.getSurfaceControl() == null) {
+50 −1
Original line number Diff line number Diff line
@@ -16,11 +16,14 @@

package com.android.wm.shell.sizecompatui;

import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -28,6 +31,8 @@ import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.res.Configuration;
import android.testing.AndroidTestingRunner;
import android.view.InsetsSource;
import android.view.InsetsState;

import androidx.test.filters.SmallTest;

@@ -35,12 +40,16 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@@ -58,12 +67,16 @@ public class SizeCompatUIControllerTest extends ShellTestCase {

    private SizeCompatUIController mController;
    private @Mock DisplayController mMockDisplayController;
    private @Mock DisplayInsetsController mMockDisplayInsetsController;
    private @Mock DisplayLayout mMockDisplayLayout;
    private @Mock DisplayImeController mMockImeController;
    private @Mock ShellTaskOrganizer.TaskListener mMockTaskListener;
    private @Mock SyncTransactionQueue mMockSyncQueue;
    private @Mock SizeCompatUILayout mMockLayout;

    @Captor
    ArgumentCaptor<OnInsetsChangedListener> mOnInsetsChangedListenerCaptor;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
@@ -72,7 +85,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
        doReturn(DISPLAY_ID).when(mMockLayout).getDisplayId();
        doReturn(TASK_ID).when(mMockLayout).getTaskId();
        mController = new SizeCompatUIController(mContext, mMockDisplayController,
                mMockImeController, mMockSyncQueue) {
                mMockDisplayInsetsController, mMockImeController, mMockSyncQueue) {
            @Override
            SizeCompatUILayout createLayout(Context context, int displayId, int taskId,
                    Configuration taskConfig, ShellTaskOrganizer.TaskListener taskListener) {
@@ -113,8 +126,18 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
        verify(mMockLayout).release();
    }

    @Test
    public void testOnDisplayAdded() {
        mController.onDisplayAdded(DISPLAY_ID);
        mController.onDisplayAdded(DISPLAY_ID + 1);

        verify(mMockDisplayInsetsController).addInsetsChangedListener(eq(DISPLAY_ID), any());
        verify(mMockDisplayInsetsController).addInsetsChangedListener(eq(DISPLAY_ID + 1), any());
    }

    @Test
    public void testOnDisplayRemoved() {
        mController.onDisplayAdded(DISPLAY_ID);
        final Configuration taskConfig = new Configuration();
        mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
                mMockTaskListener);
@@ -122,9 +145,12 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
        mController.onDisplayRemoved(DISPLAY_ID + 1);

        verify(mMockLayout, never()).release();
        verify(mMockDisplayInsetsController, never()).removeInsetsChangedListener(eq(DISPLAY_ID),
                any());

        mController.onDisplayRemoved(DISPLAY_ID);

        verify(mMockDisplayInsetsController).removeInsetsChangedListener(eq(DISPLAY_ID), any());
        verify(mMockLayout).release();
    }

@@ -144,6 +170,29 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
        verify(mMockLayout).updateDisplayLayout(mMockDisplayLayout);
    }

    @Test
    public void testInsetsChanged() {
        mController.onDisplayAdded(DISPLAY_ID);
        final Configuration taskConfig = new Configuration();
        mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
                mMockTaskListener);
        InsetsState insetsState = new InsetsState();
        InsetsSource insetsSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR);
        insetsSource.setFrame(0, 0, 1000, 1000);
        insetsState.addSource(insetsSource);

        verify(mMockDisplayInsetsController).addInsetsChangedListener(eq(DISPLAY_ID),
                mOnInsetsChangedListenerCaptor.capture());
        mOnInsetsChangedListenerCaptor.getValue().insetsChanged(insetsState);

        verify(mMockLayout).updateDisplayLayout(mMockDisplayLayout);

        // No update if the insets state is the same.
        clearInvocations(mMockLayout);
        mOnInsetsChangedListenerCaptor.getValue().insetsChanged(new InsetsState(insetsState));
        verify(mMockLayout, never()).updateDisplayLayout(mMockDisplayLayout);
    }

    @Test
    public void testChangeButtonVisibilityOnImeShowHide() {
        final Configuration taskConfig = new Configuration();
+31 −3
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.wm.shell.sizecompatui;

import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;

import static org.junit.Assert.assertFalse;
@@ -33,6 +35,8 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.view.DisplayInfo;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.View;

@@ -77,7 +81,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
        mTaskConfig = new Configuration();

        mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mCallback, mContext,
                new Configuration(), TASK_ID, mTaskListener, mDisplayLayout,
                new Configuration(), TASK_ID, mTaskListener, new DisplayLayout(),
                false /* hasShownHint */);

        spyOn(mLayout);
@@ -176,7 +180,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
        displayInfo.logicalWidth = 1000;
        displayInfo.logicalHeight = 2000;
        final DisplayLayout displayLayout1 = new DisplayLayout(displayInfo,
                mContext.getResources(), false, false);
                mContext.getResources(), /* hasNavigationBar= */ false, /* hasStatusBar= */ false);

        mLayout.updateDisplayLayout(displayLayout1);
        verify(mLayout).updateButtonSurfacePosition();
@@ -185,12 +189,36 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
        // No update if the display bounds is the same.
        clearInvocations(mLayout);
        final DisplayLayout displayLayout2 = new DisplayLayout(displayInfo,
                mContext.getResources(), false, false);
                mContext.getResources(), /* hasNavigationBar= */ false, /* hasStatusBar= */ false);
        mLayout.updateDisplayLayout(displayLayout2);
        verify(mLayout, never()).updateButtonSurfacePosition();
        verify(mLayout, never()).updateHintSurfacePosition();
    }

    @Test
    public void testUpdateDisplayLayoutInsets() {
        final DisplayInfo displayInfo = new DisplayInfo();
        displayInfo.logicalWidth = 1000;
        displayInfo.logicalHeight = 2000;
        final DisplayLayout displayLayout = new DisplayLayout(displayInfo,
                mContext.getResources(), /* hasNavigationBar= */ true, /* hasStatusBar= */ false);

        mLayout.updateDisplayLayout(displayLayout);
        verify(mLayout).updateButtonSurfacePosition();
        verify(mLayout).updateHintSurfacePosition();

        // Update if the insets change on the existing display layout
        clearInvocations(mLayout);
        InsetsState insetsState = new InsetsState();
        InsetsSource insetsSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR);
        insetsSource.setFrame(0, 0, 1000, 1000);
        insetsState.addSource(insetsSource);
        displayLayout.setInsets(mContext.getResources(), insetsState);
        mLayout.updateDisplayLayout(displayLayout);
        verify(mLayout).updateButtonSurfacePosition();
        verify(mLayout).updateHintSurfacePosition();
    }

    @Test
    public void testUpdateImeVisibility() {
        // Create button if it is not created.
+4 −3
Original line number Diff line number Diff line
@@ -156,9 +156,10 @@ public abstract class WMShellBaseModule {
    @WMSingleton
    @Provides
    static SizeCompatUIController provideSizeCompatUIController(Context context,
            DisplayController displayController, DisplayImeController imeController,
            SyncTransactionQueue syncQueue) {
        return new SizeCompatUIController(context, displayController, imeController, syncQueue);
            DisplayController displayController, DisplayInsetsController displayInsetsController,
            DisplayImeController imeController, SyncTransactionQueue syncQueue) {
        return new SizeCompatUIController(context, displayController, displayInsetsController,
                imeController, syncQueue);
    }

    @WMSingleton