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

Commit 17934b1b authored by Graciela Putri's avatar Graciela Putri Committed by Android (Google) Code Review
Browse files

Merge "Hide size compat restart button in unfolded fullscreen" into main

parents 6a1dca0e 1c075bf7
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -134,6 +134,13 @@
    <!-- Whether the additional education about reachability is enabled -->
    <bool name="config_letterboxIsReachabilityEducationEnabled">false</bool>

    <!-- The minimum tolerance of the percentage of activity bounds within its task to hide
         size compat restart button. Value lower than 0 or higher than 100 will be ignored.
         100 is the default value where the activity has to fit exactly within the task to allow
         size compat restart button to be hidden. 0 means size compat restart button will always
         be hidden. -->
    <integer name="config_letterboxRestartButtonHideTolerance">100</integer>

    <!-- Whether DragAndDrop capability is enabled -->
    <bool name="config_enableShellDragDrop">true</bool>

+24 −0
Original line number Diff line number Diff line
@@ -71,6 +71,8 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi
    private static final String HAS_SEEN_VERTICAL_REACHABILITY_EDUCATION_KEY_PREFIX =
            "has_seen_vertical_reachability_education";

    private static final int MAX_PERCENTAGE_VAL = 100;

    /**
     * The {@link SharedPreferences} instance for the restart dialog and the reachability
     * education.
@@ -82,6 +84,12 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi
     */
    private final SharedPreferences mLetterboxEduSharedPreferences;

    /**
     * The minimum tolerance of the percentage of activity bounds within its task to hide
     * size compat restart button.
     */
    private final int mHideSizeCompatRestartButtonTolerance;

    // Whether the extended restart dialog is enabled
    private boolean mIsRestartDialogEnabled;

@@ -106,6 +114,9 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi
                R.bool.config_letterboxIsRestartDialogEnabled);
        mIsReachabilityEducationEnabled = context.getResources().getBoolean(
                R.bool.config_letterboxIsReachabilityEducationEnabled);
        final int tolerance = context.getResources().getInteger(
                R.integer.config_letterboxRestartButtonHideTolerance);
        mHideSizeCompatRestartButtonTolerance = getHideSizeCompatRestartButtonTolerance(tolerance);
        mIsLetterboxRestartDialogAllowed = DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_LETTERBOX_RESTART_DIALOG,
                DEFAULT_VALUE_ENABLE_LETTERBOX_RESTART_DIALOG);
@@ -179,6 +190,10 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi
                    || !hasSeenVerticalReachabilityEducation(taskInfo));
    }

    int getHideSizeCompatRestartButtonTolerance() {
        return mHideSizeCompatRestartButtonTolerance;
    }

    boolean getHasSeenLetterboxEducation(int userId) {
        return mLetterboxEduSharedPreferences
                .getBoolean(dontShowLetterboxEduKey(userId), /* default= */ false);
@@ -218,6 +233,15 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi
        }
    }

    // Returns the minimum tolerance of the percentage of activity bounds within its task to hide
    // size compat restart button. Value lower than 0 or higher than 100 will be ignored.
    // 100 is the default value where the activity has to fit exactly within the task to allow
    // size compat restart button to be hidden. 0 means size compat restart button will always
    // be hidden.
    private int getHideSizeCompatRestartButtonTolerance(int tolerance) {
        return tolerance < 0 || tolerance > MAX_PERCENTAGE_VAL ? MAX_PERCENTAGE_VAL : tolerance;
    }

    private boolean isReachabilityEducationEnabled() {
        return mIsReachabilityEducationOverrideEnabled || (mIsReachabilityEducationEnabled
                && mIsLetterboxReachabilityEducationAllowed);
+39 −2
Original line number Diff line number Diff line
@@ -22,7 +22,9 @@ import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPL
import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
import static android.window.TaskConstants.TASK_CHILD_LAYER_COMPAT_UI;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppCompatTaskInfo;
import android.app.AppCompatTaskInfo.CameraCompatControlState;
import android.app.TaskInfo;
import android.content.Context;
@@ -33,6 +35,7 @@ import android.view.LayoutInflater;
import android.view.View;

import com.android.internal.annotations.VisibleForTesting;
import com.android.window.flags.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayLayout;
@@ -68,6 +71,8 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract {
    @VisibleForTesting
    CompatUILayout mLayout;

    private final float mHideScmTolerance;

    CompatUIWindowManager(Context context, TaskInfo taskInfo,
            SyncTransactionQueue syncQueue, CompatUICallback callback,
            ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout,
@@ -75,11 +80,13 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract {
            Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onRestartButtonClicked) {
        super(context, taskInfo, syncQueue, taskListener, displayLayout);
        mCallback = callback;
        mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat;
        mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat
                && shouldShowSizeCompatRestartButton(taskInfo);
        mCameraCompatControlState = taskInfo.appCompatTaskInfo.cameraCompatControlState;
        mCompatUIHintsState = compatUIHintsState;
        mCompatUIConfiguration = compatUIConfiguration;
        mOnRestartButtonClicked = onRestartButtonClicked;
        mHideScmTolerance = mCompatUIConfiguration.getHideSizeCompatRestartButtonTolerance();
    }

    @Override
@@ -107,6 +114,11 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract {
        mLayout = inflateLayout();
        mLayout.inject(this);

        final TaskInfo taskInfo = getLastTaskInfo();
        if (taskInfo != null) {
            mHasSizeCompat = mHasSizeCompat && shouldShowSizeCompatRestartButton(taskInfo);
        }

        updateVisibilityOfViews();

        if (mHasSizeCompat) {
@@ -127,7 +139,8 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract {
            boolean canShow) {
        final boolean prevHasSizeCompat = mHasSizeCompat;
        final int prevCameraCompatControlState = mCameraCompatControlState;
        mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat;
        mHasSizeCompat = taskInfo.appCompatTaskInfo.topActivityInSizeCompat
                && shouldShowSizeCompatRestartButton(taskInfo);
        mCameraCompatControlState = taskInfo.appCompatTaskInfo.cameraCompatControlState;

        if (!super.updateCompatInfo(taskInfo, taskListener, canShow)) {
@@ -208,6 +221,30 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract {
        updateSurfacePosition(positionX, positionY);
    }

    @VisibleForTesting
    boolean shouldShowSizeCompatRestartButton(@NonNull TaskInfo taskInfo) {
        if (!Flags.allowHideScmButton()) {
            return true;
        }
        final AppCompatTaskInfo appCompatTaskInfo = taskInfo.appCompatTaskInfo;
        final Rect taskBounds = taskInfo.configuration.windowConfiguration.getBounds();
        final int letterboxArea = computeArea(appCompatTaskInfo.topActivityLetterboxWidth,
                appCompatTaskInfo.topActivityLetterboxHeight);
        final int taskArea = computeArea(taskBounds.width(), taskBounds.height());
        if (letterboxArea == 0 || taskArea == 0) {
            return false;
        }
        final float percentageAreaOfLetterboxInTask = (float) letterboxArea / taskArea * 100;
        return percentageAreaOfLetterboxInTask < mHideScmTolerance;
    }

    private int computeArea(int width, int height) {
        if (width == 0 || height == 0) {
            return 0;
        }
        return width * height;
    }

    private void updateVisibilityOfViews() {
        if (mLayout == null) {
            return;
+43 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
import static android.app.AppCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static android.view.WindowInsets.Type.navigationBars;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -27,6 +29,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
@@ -39,6 +42,7 @@ import android.app.AppCompatTaskInfo;
import android.app.TaskInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.AndroidTestingRunner;
import android.util.Pair;
import android.view.DisplayInfo;
@@ -50,6 +54,7 @@ import android.view.View;

import androidx.test.filters.SmallTest;

import com.android.window.flags.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
@@ -59,6 +64,7 @@ import com.android.wm.shell.compatui.CompatUIController.CompatUIHintsState;
import junit.framework.Assert;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -76,6 +82,8 @@ import java.util.function.Consumer;
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class CompatUIWindowManagerTest extends ShellTestCase {
    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);

    private static final int TASK_ID = 1;

@@ -107,6 +115,7 @@ public class CompatUIWindowManagerTest extends ShellTestCase {
    public void testCreateSizeCompatButton() {
        // Doesn't create layout if show is false.
        mWindowManager.mHasSizeCompat = true;
        doReturn(true).when(mWindowManager).shouldShowSizeCompatRestartButton(mTaskInfo);
        assertTrue(mWindowManager.createLayout(/* canShow= */ false));

        verify(mWindowManager, never()).inflateLayout();
@@ -199,6 +208,7 @@ public class CompatUIWindowManagerTest extends ShellTestCase {
        // No diff
        clearInvocations(mWindowManager);
        TaskInfo taskInfo = createTaskInfo(/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN);
        doReturn(true).when(mWindowManager).shouldShowSizeCompatRestartButton(any());
        assertTrue(mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true));

        verify(mWindowManager, never()).updateSurfacePosition();
@@ -284,6 +294,7 @@ public class CompatUIWindowManagerTest extends ShellTestCase {
    @Test
    public void testUpdateCompatInfoLayoutNotInflatedYet() {
        mWindowManager.mHasSizeCompat = true;
        doReturn(true).when(mWindowManager).shouldShowSizeCompatRestartButton(any());
        mWindowManager.createLayout(/* canShow= */ false);

        verify(mWindowManager, never()).inflateLayout();
@@ -353,6 +364,7 @@ public class CompatUIWindowManagerTest extends ShellTestCase {
        // Create button if it is not created.
        mWindowManager.mLayout = null;
        mWindowManager.mHasSizeCompat = true;
        doReturn(true).when(mWindowManager).shouldShowSizeCompatRestartButton(mTaskInfo);
        mWindowManager.updateVisibility(/* canShow= */ true);

        verify(mWindowManager).createLayout(/* canShow= */ true);
@@ -464,6 +476,37 @@ public class CompatUIWindowManagerTest extends ShellTestCase {
        Assert.assertTrue(mWindowManager.needsToBeRecreated(newTaskInfo, mTaskListener));
    }

    @Test
    public void testShouldShowSizeCompatRestartButton() {
        mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_HIDE_SCM_BUTTON);

        doReturn(86).when(mCompatUIConfiguration).getHideSizeCompatRestartButtonTolerance();
        mWindowManager = new CompatUIWindowManager(mContext, mTaskInfo, mSyncTransactionQueue,
                mCallback, mTaskListener, new DisplayLayout(), new CompatUIHintsState(),
                mCompatUIConfiguration, mOnRestartButtonClicked);

        // Simulate rotation of activity in square display
        TaskInfo taskInfo = createTaskInfo(true, CAMERA_COMPAT_CONTROL_HIDDEN);
        taskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 0, 2000, 2000));
        taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = 2000;
        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
        taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = 1850;

        assertFalse(mWindowManager.shouldShowSizeCompatRestartButton(taskInfo));

        // Simulate exiting split screen/folding
        taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = 1000;
        assertTrue(mWindowManager.shouldShowSizeCompatRestartButton(taskInfo));

        // Simulate folding
        taskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 0, 1000, 2000));
        assertFalse(mWindowManager.shouldShowSizeCompatRestartButton(taskInfo));

        taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = 1000;
        taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = 500;
        assertTrue(mWindowManager.shouldShowSizeCompatRestartButton(taskInfo));
    }

    private static TaskInfo createTaskInfo(boolean hasSizeCompat,
            @AppCompatTaskInfo.CameraCompatControlState int cameraCompatControlState) {
        ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+3 −1
Original line number Diff line number Diff line
@@ -3558,9 +3558,11 @@ class Task extends TaskFragment {
                && top.mLetterboxUiController.isSystemOverrideToFullscreenEnabled();
        appCompatTaskInfo.isFromLetterboxDoubleTap = top != null
                && top.mLetterboxUiController.isFromDoubleTap();
        if (appCompatTaskInfo.isLetterboxDoubleTapEnabled) {
        if (top != null) {
            appCompatTaskInfo.topActivityLetterboxWidth = top.getBounds().width();
            appCompatTaskInfo.topActivityLetterboxHeight = top.getBounds().height();
        }
        if (appCompatTaskInfo.isLetterboxDoubleTapEnabled) {
            if (appCompatTaskInfo.isTopActivityPillarboxed()) {
                // Pillarboxed
                appCompatTaskInfo.topActivityLetterboxHorizontalPosition =