Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java +34 −3 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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. */ Loading @@ -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); Loading Loading @@ -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); } } } Loading Loading @@ -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. */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +26 −34 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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()); Loading Loading @@ -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; Loading Loading @@ -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; } } Loading @@ -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; } } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +37 −18 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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()); } /** Loading Loading @@ -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(); Loading Loading @@ -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) { Loading Loading @@ -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; } Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/extension/InsetsState.kt 0 → 100644 +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 } libs/WindowManager/Shell/tests/unittest/res/layout/caption_layout.xml 0 → 100644 +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
libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java +34 −3 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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. */ Loading @@ -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); Loading Loading @@ -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); } } } Loading Loading @@ -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. */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +26 −34 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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()); Loading Loading @@ -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; Loading Loading @@ -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; } } Loading @@ -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; } } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +37 −18 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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()); } /** Loading Loading @@ -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(); Loading Loading @@ -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) { Loading Loading @@ -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; } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/extension/InsetsState.kt 0 → 100644 +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 }
libs/WindowManager/Shell/tests/unittest/res/layout/caption_layout.xml 0 → 100644 +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