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

Commit 97c5bc38 authored by Jorge Gil's avatar Jorge Gil Committed by Android (Google) Code Review
Browse files

Merge "Update AppHandle visibility for keyguard/immersive cases" into main

parents 52dc6b46 03fea28b
Loading
Loading
Loading
Loading
+34 −3
Original line number Diff line number Diff line
@@ -47,6 +47,8 @@ public class DisplayInsetsController implements DisplayController.OnDisplaysChan
    private final SparseArray<PerDisplay> mInsetsPerDisplay = new SparseArray<>();
    private final SparseArray<CopyOnWriteArrayList<OnInsetsChangedListener>> mListeners =
            new SparseArray<>();
    private final CopyOnWriteArrayList<OnInsetsChangedListener> mGlobalListeners =
            new CopyOnWriteArrayList<>();

    public DisplayInsetsController(IWindowManager wmService,
            ShellInit shellInit,
@@ -80,6 +82,16 @@ public class DisplayInsetsController implements DisplayController.OnDisplaysChan
        }
    }

    /**
     * Adds a callback to listen for insets changes for any display. Note that the
     * listener will not be updated with the existing state of the insets on any display.
     */
    public void addGlobalInsetsChangedListener(OnInsetsChangedListener listener) {
        if (!mGlobalListeners.contains(listener)) {
            mGlobalListeners.add(listener);
        }
    }

    /**
     * Removes a callback listening for insets changes from a particular display.
     */
@@ -91,6 +103,13 @@ public class DisplayInsetsController implements DisplayController.OnDisplaysChan
        listeners.remove(listener);
    }

    /**
     * Removes a callback listening for insets changes from any display.
     */
    public void removeGlobalInsetsChangedListener(OnInsetsChangedListener listener) {
        mGlobalListeners.remove(listener);
    }

    @Override
    public void onDisplayAdded(int displayId) {
        PerDisplay pd = new PerDisplay(displayId);
@@ -138,12 +157,17 @@ public class DisplayInsetsController implements DisplayController.OnDisplaysChan

        private void insetsChanged(InsetsState insetsState) {
            CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
            if (listeners == null) {
            if (listeners == null && mGlobalListeners.isEmpty()) {
                return;
            }
            mDisplayController.updateDisplayInsets(mDisplayId, insetsState);
            for (OnInsetsChangedListener listener : mGlobalListeners) {
                listener.insetsChanged(mDisplayId, insetsState);
            }
            if (listeners != null) {
                for (OnInsetsChangedListener listener : listeners) {
                listener.insetsChanged(insetsState);
                    listener.insetsChanged(mDisplayId, insetsState);
                }
            }
        }

@@ -284,6 +308,13 @@ public class DisplayInsetsController implements DisplayController.OnDisplaysChan
         */
        default void insetsChanged(InsetsState insetsState) {}

        /**
         * Called when the window insets configuration has changed for the given display.
         */
        default void insetsChanged(int displayId, InsetsState insetsState) {
            insetsChanged(insetsState);
        }

        /**
         * Called when this window retrieved control over a specified set of insets sources.
         */
+26 −34
Original line number Diff line number Diff line
@@ -69,7 +69,6 @@ import android.view.InputChannel;
import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.InputMonitor;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.MotionEvent;
import android.view.SurfaceControl;
@@ -115,6 +114,7 @@ import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionRegionListener;
import com.android.wm.shell.windowdecor.extension.InsetsStateKt;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;

@@ -321,7 +321,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
    private void onInit() {
        mShellController.addKeyguardChangeListener(mDesktopModeKeyguardChangeListener);
        mShellCommandHandler.addDumpCallback(this::dump, this);
        mDisplayInsetsController.addInsetsChangedListener(mContext.getDisplayId(),
        mDisplayInsetsController.addGlobalInsetsChangedListener(
                new DesktopModeOnInsetsChangedListener());
        mDesktopTasksController.setOnTaskResizeAnimationListener(
                new DesktopModeOnTaskResizeAnimationListener());
@@ -1196,10 +1196,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                && mSplitScreenController.isTaskRootOrStageRoot(taskInfo.taskId)) {
            return false;
        }
        if (mDesktopModeKeyguardChangeListener.isKeyguardVisibleAndOccluded()
                && taskInfo.isFocused) {
            return false;
        }
        if (DesktopModeFlags.MODALS_POLICY.isEnabled(mContext)
                && isTopActivityExemptFromDesktopWindowing(mContext, taskInfo)) {
            return false;
@@ -1397,19 +1393,17 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        }
    }

    static class DesktopModeKeyguardChangeListener implements KeyguardChangeListener {
        private boolean mIsKeyguardVisible;
        private boolean mIsKeyguardOccluded;

    class DesktopModeKeyguardChangeListener implements KeyguardChangeListener {
        @Override
        public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
                boolean animatingDismiss) {
            mIsKeyguardVisible = visible;
            mIsKeyguardOccluded = occluded;
            final int size = mWindowDecorByTaskId.size();
            for (int i = size - 1; i >= 0; i--) {
                final DesktopModeWindowDecoration decor = mWindowDecorByTaskId.valueAt(i);
                if (decor != null) {
                    decor.onKeyguardStateChanged(visible, occluded);
                }
            }

        public boolean isKeyguardVisibleAndOccluded() {
            return mIsKeyguardVisible && mIsKeyguardOccluded;
        }
    }

@@ -1417,28 +1411,26 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
    class DesktopModeOnInsetsChangedListener implements
            DisplayInsetsController.OnInsetsChangedListener {
        @Override
        public void insetsChanged(InsetsState insetsState) {
            for (int i = 0; i < insetsState.sourceSize(); i++) {
                final InsetsSource source = insetsState.sourceAt(i);
                if (source.getType() != statusBars()) {
                    continue;
                }

                final DesktopModeWindowDecoration decor = getFocusedDecor();
        public void insetsChanged(int displayId, @NonNull InsetsState insetsState) {
            final int size = mWindowDecorByTaskId.size();
            for (int i = size - 1; i >= 0; i--) {
                final DesktopModeWindowDecoration decor = mWindowDecorByTaskId.valueAt(i);
                if (decor == null) {
                    return;
                    continue;
                }
                // If status bar inset is visible, top task is not in immersive mode
                final boolean inImmersiveMode = !source.isVisible();
                // Calls WindowDecoration#relayout if decoration visibility needs to be updated
                if (inImmersiveMode != mInImmersiveMode) {
                    if (Flags.enableDesktopWindowingImmersiveHandleHiding()) {
                        decor.relayout(decor.mTaskInfo);
                if (decor.mTaskInfo.displayId == displayId
                        && Flags.enableDesktopWindowingImmersiveHandleHiding()) {
                    decor.onInsetsStateChanged(insetsState);
                }
                    mInImmersiveMode = inImmersiveMode;
                if (!Flags.enableAdditionalWindowsAboveStatusBar()) {
                    // If status bar inset is visible, top task is not in immersive mode.
                    // This value is only needed when the App Handle input is being handled
                    // through the global input monitor (hence the flag check) to ignore gestures
                    // when the app is in immersive mode. When disabled, the view itself handles
                    // input, and since it's removed when in immersive there's no need to track
                    // this here.
                    mInImmersiveMode = !InsetsStateKt.isVisible(insetsState, statusBars());
                }

                return;
            }
        }
    }
+37 −18
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams.OccludingCaptionElement;
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer;
import com.android.wm.shell.windowdecor.extension.InsetsStateKt;

import java.util.ArrayList;
import java.util.Arrays;
@@ -143,6 +144,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
    TaskDragResizer mTaskDragResizer;
    boolean mIsCaptionVisible;

    private boolean mIsStatusBarVisible;
    private boolean mIsKeyguardVisibleAndOccluded;

    /** The most recent set of insets applied to this window decoration. */
    private WindowDecorationInsets mWindowDecorationInsets;
    private final Binder mOwner = new Binder();
@@ -184,6 +188,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        mWindowContainerTransactionSupplier = windowContainerTransactionSupplier;
        mSurfaceControlViewHostFactory = surfaceControlViewHostFactory;
        mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId);
        final InsetsState insetsState = mDisplayController.getInsetsState(mTaskInfo.displayId);
        mIsStatusBarVisible = insetsState != null
                && InsetsStateKt.isVisible(insetsState, statusBars());
    }

    /**
@@ -234,7 +241,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        }
        rootView = null; // Clear it just in case we use it accidentally

        updateCaptionVisibility(outResult.mRootView, mTaskInfo.displayId);
        updateCaptionVisibility(outResult.mRootView);

        final Rect taskBounds = mTaskInfo.getConfiguration().windowConfiguration.getBounds();
        outResult.mWidth = taskBounds.width();
@@ -284,17 +291,20 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
            mDecorWindowContext = mContext.createConfigurationContext(mWindowDecorConfig);
            mDecorWindowContext.setTheme(mContext.getThemeResId());
            if (params.mLayoutResId != 0) {
                outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext)
                        .inflate(params.mLayoutResId, null);
                outResult.mRootView = inflateLayout(mDecorWindowContext, params.mLayoutResId);
            }
        }

        if (outResult.mRootView == null) {
            outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext)
                    .inflate(params.mLayoutResId, null);
            outResult.mRootView = inflateLayout(mDecorWindowContext, params.mLayoutResId);
        }
    }

    @VisibleForTesting
    T inflateLayout(Context context, int layoutResId) {
        return (T) LayoutInflater.from(context).inflate(layoutResId, null);
    }

    private void updateDecorationContainerSurface(
            SurfaceControl.Transaction startT, RelayoutResult<T> outResult) {
        if (mDecorationContainerSurface == null) {
@@ -497,24 +507,33 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        throw new IllegalArgumentException("Unexpected alignment " + element.mAlignment);
    }

    /**
     * Checks if task has entered/exited immersive mode and requires a change in caption visibility.
     */
    private void updateCaptionVisibility(View rootView, int displayId) {
        final InsetsState insetsState = mDisplayController.getInsetsState(displayId);
        for (int i = 0; i < insetsState.sourceSize(); i++) {
            final InsetsSource source = insetsState.sourceAt(i);
            if (source.getType() != statusBars()) {
                continue;
    void onKeyguardStateChanged(boolean visible, boolean occluded) {
        final boolean prevVisAndOccluded = mIsKeyguardVisibleAndOccluded;
        mIsKeyguardVisibleAndOccluded = visible && occluded;
        final boolean changed = prevVisAndOccluded != mIsKeyguardVisibleAndOccluded;
        if (changed) {
            relayout(mTaskInfo);
        }
    }

            mIsCaptionVisible = source.isVisible();
            setCaptionVisibility(rootView, mIsCaptionVisible);
    void onInsetsStateChanged(@NonNull InsetsState insetsState) {
        final boolean prevStatusBarVisibility = mIsStatusBarVisible;
        mIsStatusBarVisible = InsetsStateKt.isVisible(insetsState, statusBars());
        final boolean changed = prevStatusBarVisibility != mIsStatusBarVisible;

            return;
        if (changed) {
            relayout(mTaskInfo);
        }
    }

    /**
     * Checks if task has entered/exited immersive mode and requires a change in caption visibility.
     */
    private void updateCaptionVisibility(View rootView) {
        mIsCaptionVisible = mIsStatusBarVisible && !mIsKeyguardVisibleAndOccluded;
        setCaptionVisibility(rootView, mIsCaptionVisible);
    }

    void setTaskDragResizer(TaskDragResizer taskDragResizer) {
        mTaskDragResizer = taskDragResizer;
    }
+33 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.wm.shell.windowdecor.extension

import android.view.InsetsState
import android.view.WindowInsets

/**
 * Whether the source of the given [type] is visible or false if there is no source of that type.
 */
fun InsetsState.isVisible(@WindowInsets.Type.InsetsType type: Int): Boolean {
    for (i in 0 until sourceSize()) {
        val source = sourceAt(i)
        if (source.type != type) {
            continue
        }
        return source.isVisible
    }
    return false
}
+23 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2024 The Android Open Source Project
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~      http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->
<com.android.wm.shell.windowdecor.WindowDecorLinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/caption"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="end"
    android:background="@drawable/caption_decor_title"/>
 No newline at end of file
Loading