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

Commit 7280cfcf authored by Jainam Shah's avatar Jainam Shah
Browse files

Fix caption bar inset sync issue

When insets are changed (system bar hidden), call to onTaskInfoChanged
happens before DisplayController has the updated value for insets. This
makes the padding in CarWindowDecoration out of sync with the state of
insets. To fix this, listen to inset changes and relayout the decoration
of all visible running tasks.

Bug: 391350956
Test: manual
Flag: com.android.systemui.car.display_compatibility_caption_bar
Change-Id: I3c9eedc252d18a3c5653504941639514a2fb64e2
parent 2016089a
Loading
Loading
Loading
Loading
+35 −3
Original line number Original line Diff line number Diff line
@@ -16,13 +16,17 @@
package com.android.wm.shell.windowdecor;
package com.android.wm.shell.windowdecor;


import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.content.Context;
import android.content.Context;
import android.hardware.input.InputManager;
import android.hardware.input.InputManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserHandle;
import android.util.Log;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseArray;
import android.view.InputDevice;
import android.view.InputDevice;
import android.view.InsetsState;
import android.view.KeyCharacterMap;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.KeyEvent;
import android.view.SurfaceControl;
import android.view.SurfaceControl;
@@ -33,6 +37,7 @@ import android.window.WindowContainerTransaction;
import com.android.wm.shell.R;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
@@ -49,7 +54,8 @@ import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSuppl
 * Works with decorations that extend {@link CarWindowDecoration}.
 * Works with decorations that extend {@link CarWindowDecoration}.
 */
 */
public abstract class CarWindowDecorViewModel
public abstract class CarWindowDecorViewModel
        implements WindowDecorViewModel, FocusTransitionListener {
        implements WindowDecorViewModel, FocusTransitionListener,
        DisplayInsetsController.OnInsetsChangedListener {
    private static final String TAG = "CarWindowDecorViewModel";
    private static final String TAG = "CarWindowDecorViewModel";


    private final ShellTaskOrganizer mTaskOrganizer;
    private final ShellTaskOrganizer mTaskOrganizer;
@@ -57,31 +63,37 @@ public abstract class CarWindowDecorViewModel
    private final @ShellBackgroundThread ShellExecutor mBgExecutor;
    private final @ShellBackgroundThread ShellExecutor mBgExecutor;
    private final ShellExecutor mMainExecutor;
    private final ShellExecutor mMainExecutor;
    private final DisplayController mDisplayController;
    private final DisplayController mDisplayController;
    private final DisplayInsetsController mDisplayInsetsController;
    private final FocusTransitionObserver mFocusTransitionObserver;
    private final FocusTransitionObserver mFocusTransitionObserver;
    private final SyncTransactionQueue mSyncQueue;
    private final SyncTransactionQueue mSyncQueue;
    private final SparseArray<CarWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
    private final SparseArray<CarWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
    private final WindowDecorViewHostSupplier<WindowDecorViewHost> mWindowDecorViewHostSupplier;
    private final WindowDecorViewHostSupplier<WindowDecorViewHost> mWindowDecorViewHostSupplier;
    private final IActivityTaskManager mActivityTaskManager;


    public CarWindowDecorViewModel(
    public CarWindowDecorViewModel(
            Context context,
            Context context,
            @ShellMainThread ShellExecutor mainExecutor,
            @ShellBackgroundThread ShellExecutor bgExecutor,
            @ShellBackgroundThread ShellExecutor bgExecutor,
            @ShellMainThread ShellExecutor shellExecutor,
            ShellInit shellInit,
            ShellInit shellInit,
            ShellTaskOrganizer taskOrganizer,
            ShellTaskOrganizer taskOrganizer,
            DisplayController displayController,
            DisplayController displayController,
            DisplayInsetsController displayInsetsController,
            SyncTransactionQueue syncQueue,
            SyncTransactionQueue syncQueue,
            FocusTransitionObserver focusTransitionObserver,
            FocusTransitionObserver focusTransitionObserver,
            WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier) {
            WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier) {
        mContext = context;
        mContext = context;
        mMainExecutor = shellExecutor;
        mMainExecutor = mainExecutor;
        mBgExecutor = bgExecutor;
        mBgExecutor = bgExecutor;
        mTaskOrganizer = taskOrganizer;
        mTaskOrganizer = taskOrganizer;
        mDisplayController = displayController;
        mDisplayController = displayController;
        mDisplayInsetsController = displayInsetsController;
        mFocusTransitionObserver = focusTransitionObserver;
        mFocusTransitionObserver = focusTransitionObserver;
        mSyncQueue = syncQueue;
        mSyncQueue = syncQueue;
        mWindowDecorViewHostSupplier = windowDecorViewHostSupplier;
        mWindowDecorViewHostSupplier = windowDecorViewHostSupplier;
        mActivityTaskManager = ActivityTaskManager.getService();


        shellInit.addInitCallback(this::onInit, this);
        shellInit.addInitCallback(this::onInit, this);
        displayInsetsController.addGlobalInsetsChangedListener(this);
    }
    }


    private void onInit() {
    private void onInit() {
@@ -187,6 +199,26 @@ public abstract class CarWindowDecorViewModel
        decoration.close();
        decoration.close();
    }
    }


    @Override
    public void insetsChanged(int displayId, InsetsState insetsState) {
        final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
        try {
            mActivityTaskManager.getTasks(/* maxNum= */ Integer.MAX_VALUE,
                            /* filterOnlyVisibleRecents= */ false, /* keepIntentExtra= */ false,
                            displayId)
                    .stream().filter(taskInfo -> taskInfo.isVisible && taskInfo.isRunning)
                    .forEach(taskInfo -> {
                        final CarWindowDecoration decoration = mWindowDecorByTaskId.get(
                                taskInfo.taskId);
                        if (decoration != null) {
                            decoration.relayout(taskInfo, t, t);
                        }
                    });
        } catch (RemoteException e) {
            Log.e(TAG, "Cannot update decoration on inset change on displayId: " + displayId);
        }
    }

    /**
    /**
     * @return {@code true} if the task/activity associated with {@code taskInfo} should show
     * @return {@code true} if the task/activity associated with {@code taskInfo} should show
     * window decoration.
     * window decoration.
+14 −14
Original line number Original line Diff line number Diff line
@@ -30,7 +30,6 @@ import android.view.WindowInsets;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransaction;


import androidx.annotation.NonNull;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;


import com.android.wm.shell.R;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -47,6 +46,7 @@ public class CarWindowDecoration extends WindowDecoration<WindowDecorLinearLayou
    private WindowDecorLinearLayout mRootView;
    private WindowDecorLinearLayout mRootView;
    private @ShellBackgroundThread final ShellExecutor mBgExecutor;
    private @ShellBackgroundThread final ShellExecutor mBgExecutor;
    private final View.OnClickListener mClickListener;
    private final View.OnClickListener mClickListener;
    private final RelayoutParams mRelayoutParams = new RelayoutParams();
    private final RelayoutResult<WindowDecorLinearLayout> mResult = new RelayoutResult<>();
    private final RelayoutResult<WindowDecorLinearLayout> mResult = new RelayoutResult<>();


    CarWindowDecoration(
    CarWindowDecoration(
@@ -75,7 +75,8 @@ public class CarWindowDecoration extends WindowDecoration<WindowDecorLinearLayou
    @SuppressLint("MissingPermission")
    @SuppressLint("MissingPermission")
    void relayout(ActivityManager.RunningTaskInfo taskInfo,
    void relayout(ActivityManager.RunningTaskInfo taskInfo,
            SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) {
            SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) {
        relayout(taskInfo, startT, finishT, /* isCaptionVisible= */ true);
        relayout(taskInfo, startT, finishT,
                /* isCaptionVisible= */ mRelayoutParams.mIsCaptionVisible);
    }
    }


    @SuppressLint("MissingPermission")
    @SuppressLint("MissingPermission")
@@ -84,12 +85,9 @@ public class CarWindowDecoration extends WindowDecoration<WindowDecorLinearLayou
            boolean isCaptionVisible) {
            boolean isCaptionVisible) {
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerTransaction wct = new WindowContainerTransaction();


        RelayoutParams relayoutParams = new RelayoutParams();
        updateRelayoutParams(mRelayoutParams, taskInfo, isCaptionVisible);


        updateRelayoutParams(relayoutParams, taskInfo,
        relayout(mRelayoutParams, startT, finishT, wct, mRootView, mResult);
                mDisplayController.getInsetsState(taskInfo.displayId), isCaptionVisible);

        relayout(relayoutParams, startT, finishT, wct, mRootView, mResult);
        // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
        // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
        mBgExecutor.execute(() -> mTaskOrganizer.applyTransaction(wct));
        mBgExecutor.execute(() -> mTaskOrganizer.applyTransaction(wct));


@@ -118,7 +116,6 @@ public class CarWindowDecoration extends WindowDecoration<WindowDecorLinearLayou
    private void updateRelayoutParams(
    private void updateRelayoutParams(
            RelayoutParams relayoutParams,
            RelayoutParams relayoutParams,
            ActivityManager.RunningTaskInfo taskInfo,
            ActivityManager.RunningTaskInfo taskInfo,
            @Nullable InsetsState displayInsetsState,
            boolean isCaptionVisible) {
            boolean isCaptionVisible) {
        relayoutParams.reset();
        relayoutParams.reset();
        relayoutParams.mRunningTaskInfo = taskInfo;
        relayoutParams.mRunningTaskInfo = taskInfo;
@@ -127,16 +124,19 @@ public class CarWindowDecoration extends WindowDecoration<WindowDecorLinearLayou
        relayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height;
        relayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height;
        relayoutParams.mIsCaptionVisible =
        relayoutParams.mIsCaptionVisible =
                isCaptionVisible && mIsStatusBarVisible && !mIsKeyguardVisibleAndOccluded;
                isCaptionVisible && mIsStatusBarVisible && !mIsKeyguardVisibleAndOccluded;
        if (displayInsetsState != null) {
        relayoutParams.mCaptionTopPadding = getTopPadding(taskInfo, relayoutParams);
            relayoutParams.mCaptionTopPadding = getTopPadding(

                    taskInfo.getConfiguration().windowConfiguration.getBounds(),
                    displayInsetsState);
        }
        relayoutParams.mInsetSourceFlags |= FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
        relayoutParams.mInsetSourceFlags |= FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR;
        relayoutParams.mApplyStartTransactionOnDraw = true;
        relayoutParams.mApplyStartTransactionOnDraw = true;
    }
    }


    private static int getTopPadding(Rect taskBounds, @NonNull InsetsState insetsState) {
    private int getTopPadding(ActivityManager.RunningTaskInfo taskInfo,
            RelayoutParams relayoutParams) {
        Rect taskBounds = taskInfo.getConfiguration().windowConfiguration.getBounds();
        InsetsState insetsState = mDisplayController.getInsetsState(taskInfo.displayId);
        if (insetsState == null) {
            return relayoutParams.mCaptionTopPadding;
        }
        Insets systemDecor = insetsState.calculateInsets(taskBounds,
        Insets systemDecor = insetsState.calculateInsets(taskBounds,
                WindowInsets.Type.systemBars() & ~WindowInsets.Type.captionBar(),
                WindowInsets.Type.systemBars() & ~WindowInsets.Type.captionBar(),
                false /* ignoreVisibility */);
                false /* ignoreVisibility */);