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

Commit e6e6fb89 authored by Jorge Gil's avatar Jorge Gil
Browse files

Add INPUT_FEATURE_NO_INPUT_CHANNEL feature to app handle

The app handle doesn't need input features because its input is actually
handled by the InputMonitor in DesktopModeWindowDecorViewModel. Adding
this flags skips a IWindowSession::grantInputChannel, which helps with
jank when opening a fullscreen/split-screen task.

This change also unifies this new param with
mAllowCaptionInputFallthrough into a RelayoutParams#inputFeatures field.

Bug: 335975211
Test: atest WMShellUnitTests
Test: manual - app handle in fullscreen/split works as usual
Change-Id: I1b3b736e92a23f59d8174586da2902cff5ba5793
parent de688c1b
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -200,7 +200,6 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
        mRelayoutParams.mShadowRadiusId = shadowRadiusID;
        mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
        mRelayoutParams.mSetTaskPositionAndCrop = setTaskCropAndPosition;
        mRelayoutParams.mAllowCaptionInputFallthrough = false;

        relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
        // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
+12 −5
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.window.WindowContainerTransaction;

@@ -340,11 +341,12 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId);

        if (captionLayoutId == R.layout.desktop_mode_app_controls_window_decor) {
            // If the app is requesting to customize the caption bar, allow input to fall through
            // to the windows below so that the app can respond to input events on their custom
            // content.
            relayoutParams.mAllowCaptionInputFallthrough =
                    TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo);
            if (TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
                // If the app is requesting to customize the caption bar, allow input to fall
                // through to the windows below so that the app can respond to input events on
                // their custom content.
                relayoutParams.mInputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_SPY;
            }
            // Report occluding elements as bounding rects to the insets system so that apps can
            // draw in the empty space in the center:
            //   First, the "app chip" section of the caption bar (+ some extra margins).
@@ -359,6 +361,11 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
            controlsElement.mWidthResId = R.dimen.desktop_mode_customizable_caption_margin_end;
            controlsElement.mAlignment = RelayoutParams.OccludingCaptionElement.Alignment.END;
            relayoutParams.mOccludingCaptionElements.add(controlsElement);
        } else if (captionLayoutId == R.layout.desktop_mode_focused_window_decor) {
            // The focused decor (fullscreen/split) does not need to handle input because input in
            // the App Handle is handled by the InputMonitor in DesktopModeWindowDecorViewModel.
            relayoutParams.mInputFeatures
                    |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
        }
        if (DesktopModeStatus.useWindowShadow(/* isFocusedWindow= */ taskInfo.isFocused)) {
            relayoutParams.mShadowRadiusId = taskInfo.isFocused
+9 −9
Original line number Diff line number Diff line
@@ -312,7 +312,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
                boundingRects = null;
            } else {
                // The customizable region can at most be equal to the caption bar.
                if (params.mAllowCaptionInputFallthrough) {
                if (params.hasInputFeatureSpy()) {
                    outResult.mCustomizableCaptionRegion.set(mCaptionInsetsRect);
                }
                boundingRects = new Rect[numOfElements];
@@ -325,7 +325,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
                            calculateBoundingRect(element, elementWidthPx, mCaptionInsetsRect);
                    // Subtract the regions used by the caption elements, the rest is
                    // customizable.
                    if (params.mAllowCaptionInputFallthrough) {
                    if (params.hasInputFeatureSpy()) {
                        outResult.mCustomizableCaptionRegion.op(boundingRects[i],
                                Region.Op.DIFFERENCE);
                    }
@@ -396,11 +396,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
                        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
        lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
        lp.setTrustedOverlay();
        if (params.mAllowCaptionInputFallthrough) {
            lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_SPY;
        } else {
            lp.inputFeatures &= ~WindowManager.LayoutParams.INPUT_FEATURE_SPY;
        }
        lp.inputFeatures = params.mInputFeatures;
        if (mViewHost == null) {
            mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay,
                    mCaptionWindowManager);
@@ -608,7 +604,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        int mCaptionHeightId;
        int mCaptionWidthId;
        final List<OccludingCaptionElement> mOccludingCaptionElements = new ArrayList<>();
        boolean mAllowCaptionInputFallthrough;
        int mInputFeatures;

        int mShadowRadiusId;
        int mCornerRadius;
@@ -623,7 +619,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
            mCaptionHeightId = Resources.ID_NULL;
            mCaptionWidthId = Resources.ID_NULL;
            mOccludingCaptionElements.clear();
            mAllowCaptionInputFallthrough = false;
            mInputFeatures = 0;

            mShadowRadiusId = Resources.ID_NULL;
            mCornerRadius = 0;
@@ -633,6 +629,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
            mWindowDecorConfig = null;
        }

        boolean hasInputFeatureSpy() {
            return (mInputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_SPY) != 0;
        }

        /**
         * Describes elements within the caption bar that could occlude app content, and should be
         * sent as bounding rectangles to the insets system.
+58 −3
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.wm.shell.windowdecor;

import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND;

import static com.google.common.truth.Truth.assertThat;
@@ -44,6 +45,7 @@ import android.view.Choreographer;
import android.view.Display;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.WindowManager;
import android.window.WindowContainerTransaction;

import androidx.test.filters.SmallTest;
@@ -187,7 +189,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
                /* applyStartTransactionOnDraw= */ true,
                /* shouldSetTaskPositionAndCrop */ false);

        assertThat(relayoutParams.mAllowCaptionInputFallthrough).isTrue();
        assertThat(relayoutParams.hasInputFeatureSpy()).isTrue();
    }

    @Test
@@ -204,7 +206,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
                /* applyStartTransactionOnDraw= */ true,
                /* shouldSetTaskPositionAndCrop */ false);

        assertThat(relayoutParams.mAllowCaptionInputFallthrough).isFalse();
        assertThat(relayoutParams.hasInputFeatureSpy()).isFalse();
    }

    @Test
@@ -220,7 +222,55 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
                /* applyStartTransactionOnDraw= */ true,
                /* shouldSetTaskPositionAndCrop */ false);

        assertThat(relayoutParams.mAllowCaptionInputFallthrough).isFalse();
        assertThat(relayoutParams.hasInputFeatureSpy()).isFalse();
    }

    @Test
    public void updateRelayoutParams_freeform_inputChannelNeeded() {
        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
        final RelayoutParams relayoutParams = new RelayoutParams();

        DesktopModeWindowDecoration.updateRelayoutParams(
                relayoutParams,
                mTestableContext,
                taskInfo,
                /* applyStartTransactionOnDraw= */ true,
                /* shouldSetTaskPositionAndCrop */ false);

        assertThat(hasNoInputChannelFeature(relayoutParams)).isFalse();
    }

    @Test
    public void updateRelayoutParams_fullscreen_inputChannelNotNeeded() {
        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
        final RelayoutParams relayoutParams = new RelayoutParams();

        DesktopModeWindowDecoration.updateRelayoutParams(
                relayoutParams,
                mTestableContext,
                taskInfo,
                /* applyStartTransactionOnDraw= */ true,
                /* shouldSetTaskPositionAndCrop */ false);

        assertThat(hasNoInputChannelFeature(relayoutParams)).isTrue();
    }

    @Test
    public void updateRelayoutParams_multiwindow_inputChannelNotNeeded() {
        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        final RelayoutParams relayoutParams = new RelayoutParams();

        DesktopModeWindowDecoration.updateRelayoutParams(
                relayoutParams,
                mTestableContext,
                taskInfo,
                /* applyStartTransactionOnDraw= */ true,
                /* shouldSetTaskPositionAndCrop */ false);

        assertThat(hasNoInputChannelFeature(relayoutParams)).isTrue();
    }

    private void fillRoundedCornersResources(int fillValue) {
@@ -268,4 +318,9 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
        return taskInfo;

    }

    private static boolean hasNoInputChannelFeature(RelayoutParams params) {
        return (params.mInputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL)
                != 0;
    }
}