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

Commit 84976417 authored by Ats Jenk's avatar Ats Jenk Committed by Android (Google) Code Review
Browse files

Merge "Check for display cutout for status bar height" into main

parents 3afd3041 10ecfcb5
Loading
Loading
Loading
Loading
+9 −5
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import android.graphics.drawable.GradientDrawable;
import android.os.Handler;
import android.util.Size;
import android.view.Choreographer;
import android.view.Display;
import android.view.InsetsState;
import android.view.MotionEvent;
import android.view.SurfaceControl;
@@ -67,6 +68,8 @@ import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;

import java.util.function.BiFunction;

/**
 * Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
 * {@link CaptionWindowDecorViewModel}. The caption bar contains a back button, minimize button,
@@ -218,7 +221,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
        relayoutParams.reset();
        relayoutParams.mRunningTaskInfo = taskInfo;
        relayoutParams.mLayoutResId = R.layout.caption_window_decor;
        relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
        relayoutParams.mCaptionHeightCalculator = getCaptionHeightCalculator();
        if (DesktopExperienceFlags.ENABLE_DYNAMIC_RADIUS_COMPUTATION_BUGFIX.isTrue()) {
            relayoutParams.mShadowRadiusId = hasGlobalFocus
                    ? R.dimen.freeform_decor_shadow_focused_thickness
@@ -445,12 +448,13 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
    }

    @Override
    int getCaptionHeightId(@WindowingMode int windowingMode) {
        return getCaptionHeightIdStatic(windowingMode);
    int getCaptionHeight(@WindowingMode int windowingMode) {
        return getCaptionHeightCalculator().apply(mContext, mDisplay);
    }

    private static int getCaptionHeightIdStatic(@WindowingMode int windowingMode) {
        return R.dimen.freeform_decor_caption_height;
    private static BiFunction<Context, Display, Integer> getCaptionHeightCalculator() {
        return (ctx, display) -> loadDimensionPixelSize(ctx.getResources(),
                R.dimen.freeform_decor_caption_height);
    }

    @Override
+2 −1
Original line number Diff line number Diff line
@@ -135,7 +135,8 @@ public class CarWindowDecoration extends WindowDecoration<WindowDecorLinearLayou
        relayoutParams.mRunningTaskInfo = taskInfo;
        // todo(b/382071404): update to car specific UI
        relayoutParams.mLayoutResId = R.layout.caption_window_decor;
        relayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height;
        relayoutParams.mCaptionHeightCalculator = (ctx, display) ->
                loadDimensionPixelSize(ctx.getResources(), R.dimen.freeform_decor_caption_height);
        relayoutParams.mIsCaptionVisible =
                isCaptionVisible && mIsStatusBarVisible && !mIsKeyguardVisibleAndOccluded;
        relayoutParams.mCaptionTopPadding = getTopPadding(taskInfo, relayoutParams);
+18 −12
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ import android.os.Trace;
import android.os.UserHandle;
import android.util.Size;
import android.view.Choreographer;
import android.view.Display;
import android.view.InsetsState;
import android.view.MotionEvent;
import android.view.SurfaceControl;
@@ -78,6 +79,7 @@ import android.window.TaskSnapshot;
import android.window.WindowContainerTransaction;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.SystemBarUtils;
import com.android.window.flags.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
@@ -122,6 +124,7 @@ import kotlinx.coroutines.MainCoroutineDispatcher;

import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;

@@ -973,7 +976,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        relayoutParams.reset();
        relayoutParams.mRunningTaskInfo = taskInfo;
        relayoutParams.mLayoutResId = captionLayoutId;
        relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
        relayoutParams.mCaptionHeightCalculator = getCaptionHeightCalculator(
                taskInfo.getWindowingMode());
        relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId);
        relayoutParams.mHasGlobalFocus = hasGlobalFocus;
        relayoutParams.mDisplayExclusionRegion.set(displayExclusionRegion);
@@ -1850,19 +1854,21 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        return mResult.mCaptionX;
    }

    @Override
    int getCaptionHeightId(@WindowingMode int windowingMode) {
        return getCaptionHeightIdStatic(windowingMode);
    private static BiFunction<Context, Display, Integer> getCaptionHeightCalculator(
            @WindowingMode int windowingMode) {
        return (ctx, display) -> {
            if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
                return SystemBarUtils.getStatusBarHeight(ctx.getResources(), display.getCutout());
            } else {
                return loadDimensionPixelSize(ctx.getResources(),
                        getDesktopViewAppHeaderHeightId());
            }

    private static int getCaptionHeightIdStatic(@WindowingMode int windowingMode) {
        return windowingMode == WINDOWING_MODE_FULLSCREEN
                ? com.android.internal.R.dimen.status_bar_height_default
                : getDesktopViewAppHeaderHeightId();
        };
    }

    private int getCaptionHeight(@WindowingMode int windowingMode) {
        return loadDimensionPixelSize(mContext.getResources(), getCaptionHeightId(windowingMode));
    @Override
    int getCaptionHeight(@WindowingMode int windowingMode) {
        return getCaptionHeightCalculator(windowingMode).apply(mContext, mDisplay);
    }

    @Override
+9 −9
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Supplier;

/**
@@ -281,8 +282,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        outResult.mHeight = taskBounds.height();
        outResult.mRootView.setTaskFocusState(mHasGlobalFocus);
        final Resources resources = mDecorWindowContext.getResources();
        outResult.mCaptionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId)
                + params.mCaptionTopPadding;
        outResult.mCaptionHeight = params.mCaptionHeightCalculator.apply(mDecorWindowContext,
                mDisplay) + params.mCaptionTopPadding;
        outResult.mCaptionWidth = params.mCaptionWidthId != Resources.ID_NULL
                ? loadDimensionPixelSize(resources, params.mCaptionWidthId) : taskBounds.width();
        outResult.mCaptionX = (outResult.mWidth - outResult.mCaptionWidth) / 2;
@@ -673,8 +674,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        captionView.setVisibility(v);
    }

    int getCaptionHeightId(@WindowingMode int windowingMode) {
        return Resources.ID_NULL;
    int getCaptionHeight(@WindowingMode int windowingMode) {
        return 0;
    }

    int getCaptionViewId() {
@@ -822,12 +823,11 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
     * Adds caption inset source to a WCT
     */
    public void addCaptionInset(WindowContainerTransaction wct) {
        final int captionHeightId = getCaptionHeightId(mTaskInfo.getWindowingMode());
        if (captionHeightId == Resources.ID_NULL || !mIsCaptionVisible) {
        final int captionHeight = getCaptionHeight(mTaskInfo.getWindowingMode());
        if (captionHeight == 0 || !mIsCaptionVisible) {
            return;
        }

        final int captionHeight = loadDimensionPixelSize(mContext.getResources(), captionHeightId);
        final Rect captionInsets = new Rect(0, 0, 0, captionHeight);
        final WindowDecorationInsets newInsets = new WindowDecorationInsets(mTaskInfo.token,
                mOwner, captionInsets, null  /* taskFrame */,  null /* boundingRects */,
@@ -841,7 +841,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
    static class RelayoutParams {
        RunningTaskInfo mRunningTaskInfo;
        int mLayoutResId;
        int mCaptionHeightId;
        BiFunction<Context, Display, Integer> mCaptionHeightCalculator = (ctx, display) -> 0;
        int mCaptionWidthId;
        final List<OccludingCaptionElement> mOccludingCaptionElements = new ArrayList<>();
        boolean mLimitTouchRegionToSystemAreas;
@@ -872,7 +872,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>

        void reset() {
            mLayoutResId = Resources.ID_NULL;
            mCaptionHeightId = Resources.ID_NULL;
            mCaptionHeightCalculator = (ctx, display) -> 0;
            mCaptionWidthId = Resources.ID_NULL;
            mOccludingCaptionElements.clear();
            mLimitTouchRegionToSystemAreas = false;
+62 −3
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
@@ -75,6 +76,7 @@ import android.testing.TestableLooper;
import android.view.AttachedSurfaceControl;
import android.view.Choreographer;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.GestureDetector;
import android.view.InsetsSource;
import android.view.InsetsState;
@@ -101,6 +103,7 @@ import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser;
import com.android.wm.shell.apptoweb.AssistContentRequester;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.MultiInstanceHelper;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -179,6 +182,10 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
    @Mock
    private DisplayController mMockDisplayController;
    @Mock
    private Display mDefaultDisplay;
    @Mock
    private DisplayLayout mDisplayLayout;
    @Mock
    private SplitScreenController mMockSplitScreenController;
    @Mock
    private ShellTaskOrganizer mMockShellTaskOrganizer;
@@ -299,9 +306,10 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
        final ResolveInfo resolveInfo = createResolveInfo(false /* handleAllWebDataUri */);
        when(mMockPackageManager.resolveActivityAsUser(any(), anyInt(), anyInt()))
                .thenReturn(resolveInfo);
        final Display defaultDisplay = mock(Display.class);
        doReturn(defaultDisplay).when(mMockDisplayController).getDisplay(Display.DEFAULT_DISPLAY);
        doReturn(mDefaultDisplay).when(mMockDisplayController).getDisplay(Display.DEFAULT_DISPLAY);
        doReturn(mInsetsState).when(mMockDisplayController).getInsetsState(anyInt());
        doReturn(mDisplayLayout).when(mMockDisplayController).getDisplayLayout(
                Display.DEFAULT_DISPLAY);
        when(mMockHandleMenuFactory.create(any(), any(), any(), any(), any(), anyInt(), any(),
                anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(),
                anyBoolean(), any(), any(), anyInt(), anyInt(), anyInt(), anyInt()))
@@ -316,7 +324,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
                .thenReturn(mMockAppHandleViewHolder);
        when(mMockDesktopUserRepositories.getCurrent()).thenReturn(mDesktopRepository);
        when(mMockDesktopUserRepositories.getProfile(anyInt())).thenReturn(mDesktopRepository);
        when(mMockWindowDecorViewHostSupplier.acquire(any(), eq(defaultDisplay)))
        when(mMockWindowDecorViewHostSupplier.acquire(any(), eq(mDefaultDisplay)))
                .thenReturn(mMockWindowDecorViewHost);
        when(mMockWindowDecorViewHost.getSurfaceControl()).thenReturn(mock(SurfaceControl.class));
    }
@@ -1121,6 +1129,46 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
        assertThat(relayoutParams.mAsyncViewHost).isFalse();
    }

    @Test
    public void updateRelayoutParams_handle_hasDisplayCutout_useCutoutInCaptionHeight() {
        // Have cutout be larger than status bar so we use cutout as the caption height
        int statusBarHeight = mContext.getResources().getDimensionPixelSize(
                R.dimen.status_bar_height_default);
        int cutoutSize = statusBarHeight + 100;
        DisplayCutout cutout = createDisplayCutout(cutoutSize);
        when(mDefaultDisplay.getCutout()).thenReturn(cutout);

        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
        createWindowDecoration(taskInfo, /* relayout= */ true);

        ArgumentCaptor<WindowManager.LayoutParams> captor = ArgumentCaptor.forClass(
                WindowManager.LayoutParams.class);
        verify(mMockWindowDecorViewHost).updateViewAsync(any(), captor.capture(), any(), any());
        WindowManager.LayoutParams lp = captor.getValue();
        assertThat(lp.height).isEqualTo(cutoutSize);
    }

    @Test
    public void updateRelayoutParams_header_hasDisplayCutout_ignoreCutoutInCaptionHeight() {
        // Have cutout be larger than desktop header so it would affect the size if used
        int desktopHeaderHeight = mContext.getResources().getDimensionPixelSize(
                R.dimen.desktop_view_default_header_height);
        int cutoutHeight = desktopHeaderHeight + 100;
        DisplayCutout cutout = createDisplayCutout(cutoutHeight);
        when(mDefaultDisplay.getCutout()).thenReturn(cutout);

        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
        createWindowDecoration(taskInfo, /* relayout= */ true);

        ArgumentCaptor<WindowManager.LayoutParams> captor = ArgumentCaptor.forClass(
                WindowManager.LayoutParams.class);
        verify(mMockWindowDecorViewHost).updateView(any(), captor.capture(), any(), any(), any());
        WindowManager.LayoutParams lp = captor.getValue();
        assertThat(lp.height).isEqualTo(desktopHeaderHeight);
    }

    @Test
    public void relayout_fullscreenTask_appliesTransactionImmediately() {
        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
@@ -1884,6 +1932,17 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
        return createInsetsState(List.of(source));
    }

    private static DisplayCutout createDisplayCutout(int cutoutSize) {
        Insets safeInsets = Insets.of(0, cutoutSize, 0, 0);
        DisplayCutout cutout = new DisplayCutout(
                safeInsets,
                /* boundLeft= */ null,
                /* boundTop= */ new Rect(0, 0, cutoutSize, cutoutSize),
                /* boundRight= */ null,
                /* boundBottom= */ null);
        return cutout;
    }

    private static class TestTouchEventListener extends GestureDetector.SimpleOnGestureListener
            implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener,
            View.OnGenericMotionListener, DragDetector.MotionEventHandler {
Loading