Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/LockTaskChangeListener.kt 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.common import android.app.ActivityManager.LOCK_TASK_MODE_NONE import com.android.wm.shell.sysui.ShellInit /** * A component for observing changes to the system's LockTask mode. * * This class listens for changes to LockTaskMode from [TaskStackListenerImpl] and keeps a cache of * the current LockTask mode (LOCK_TASK_MODE_NONE, LOCK_TASK_MODE_LOCKED, LOCK_TASK_MODE_PINNED). * It provides a listener interface for other components to subscribe to these changes, * allowing them to react when a task becomes locked or unlocked. * * To use this class, obtain an instance and register a [LockTaskModeChangedListener] via * the [addListener] method. */ class LockTaskChangeListener( shellInit: ShellInit, private val taskStackListenerImpl: TaskStackListenerImpl, ) : TaskStackListenerCallback { /** Listener for lock task mode changes. */ fun interface LockTaskModeChangedListener { /** Called when the lock task mode changes. */ fun onLockTaskModeChanged(mode: Int) } private var lockTaskMode = LOCK_TASK_MODE_NONE val isTaskLocked get() = lockTaskMode != LOCK_TASK_MODE_NONE private val listeners = linkedSetOf<LockTaskModeChangedListener>() init { shellInit.addInitCallback(::onInit, this) } private fun onInit() { taskStackListenerImpl.addListener(this) } /** Adds a listener for lock task mode changes. */ fun addListener(listener: LockTaskModeChangedListener) { listeners.add(listener) } /** Removes a listener for lock task mode changes. */ fun removeListener(listener: LockTaskModeChangedListener) { listeners.remove(listener) } override fun onLockTaskModeChanged(mode: Int) { lockTaskMode = mode // Notify all registered listeners listeners.forEach { it.onLockTaskModeChanged(lockTaskMode) } } } libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java +2 −0 Original line number Diff line number Diff line Loading @@ -93,4 +93,6 @@ public interface TaskStackListenerCallback { default void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { } default void onActivityRotation(int displayId) { } default void onLockTaskModeChanged(int mode) { } } libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java +12 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler. private static final int ON_TASK_DESCRIPTION_CHANGED = 19; private static final int ON_ACTIVITY_ROTATION = 20; private static final int ON_RECENT_TASK_REMOVED_FOR_ADD_TASK = 21; private static final int ON_LOCK_TASK_MODE_CHANGE = 22; /** * List of {@link TaskStackListenerCallback} registered from {@link #addListener}. Loading Loading @@ -137,6 +138,11 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler. mMainHandler.obtainMessage(ON_RECENT_TASK_REMOVED_FOR_ADD_TASK, taskId).sendToTarget(); } @Override public void onLockTaskModeChanged(int mode) { mMainHandler.obtainMessage(ON_LOCK_TASK_MODE_CHANGE, mode, 0 /* unused */).sendToTarget(); } @Override public void onTaskStackChanged() { // Call the task changed callback for the non-ui thread listeners first. Copy to a set Loading Loading @@ -435,6 +441,12 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler. } break; } case ON_LOCK_TASK_MODE_CHANGE: { for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { mTaskStackListeners.get(i).onLockTaskModeChanged(msg.arg1); } break; } } } if (msg.obj instanceof SomeArgs) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +12 −2 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.HomeIntentProvider; import com.android.wm.shell.common.LaunchAdjacentController; import com.android.wm.shell.common.LockTaskChangeListener; import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorController; import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorSurface; import com.android.wm.shell.common.MultiInstanceHelper; Loading Loading @@ -1239,7 +1240,8 @@ public abstract class WMShellModule { DesksOrganizer desksOrganizer, ShellDesktopState shelldesktopState, DesktopConfig desktopConfig, UserProfileContexts userProfileContexts UserProfileContexts userProfileContexts, LockTaskChangeListener lockTaskChangeListener ) { if (!shelldesktopState.canEnterDesktopModeOrShowAppHandle()) { return Optional.empty(); Loading @@ -1258,7 +1260,15 @@ public abstract class WMShellModule { desktopModeUiEventLogger, taskResourceLoader, recentsTransitionHandler, desktopModeCompatPolicy, desktopTilingDecorViewModel, multiDisplayDragMoveIndicatorController, compatUI.orElse(null), desksOrganizer, shelldesktopState, desktopConfig, userProfileContexts)); desksOrganizer, shelldesktopState, desktopConfig, userProfileContexts, lockTaskChangeListener)); } @WMSingleton @Provides static LockTaskChangeListener provideLockTaskChangeListener(ShellInit shellInit, TaskStackListenerImpl taskStackListenerImpl) { return new LockTaskChangeListener(shellInit, taskStackListenerImpl); } @WMSingleton Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DefaultWindowDecoration.kt +23 −5 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser import com.android.wm.shell.apptoweb.AppToWebRepository import com.android.wm.shell.apptoweb.AssistContentRequester import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.LockTaskChangeListener import com.android.wm.shell.common.MultiInstanceHelper import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.common.SyncTransactionQueue Loading Loading @@ -134,6 +135,7 @@ class DefaultWindowDecoration @JvmOverloads constructor( private val windowContainerTransactionSupplier: () -> WindowContainerTransaction = { WindowContainerTransaction() }, surfaceControlSupplier: () -> SurfaceControl = { SurfaceControl() }, private val lockTaskChangeListener: LockTaskChangeListener ) : WindowDecoration2<WindowDecorLinearLayout>( taskInfo, context, Loading Loading @@ -493,7 +495,7 @@ class DefaultWindowDecoration @JvmOverloads constructor( cornerRadiusId = getCornerRadiusId(captionType, shouldIgnoreCornerRadius), borderSettingsId = getBorderSettingsId(captionType, taskInfo, hasGlobalFocus), boxShadowSettingsIds = getShadowSettingsIds(captionType, hasGlobalFocus), isCaptionVisible = shouldShowCaption(taskInfo), isCaptionVisible = shouldShowCaption(taskInfo, lockTaskChangeListener.isTaskLocked), windowDecorConfig = windowDecorConfig, asyncViewHost = asyncViewHost, applyStartTransactionOnDraw = applyStartTransactionOnDraw, Loading Loading @@ -611,13 +613,20 @@ class DefaultWindowDecoration @JvmOverloads constructor( } private fun shouldShowCaption(taskInfo: RunningTaskInfo): Boolean = private fun shouldShowCaption(taskInfo: RunningTaskInfo, isTaskLocked: Boolean): Boolean { var showCaption: Boolean if (DesktopModeFlags.ENABLE_DESKTOP_IMMERSIVE_DRAG_BUGFIX.isTrue && isDragging) { // If the task is being dragged, the caption should not be hidden so that it continues // receiving input true showCaption = true } else if (DesktopModeFlags.ENABLE_FULLY_IMMERSIVE_IN_DESKTOP.isTrue && inFullImmersive) { isStatusBarVisible && !isKeyguardVisibleAndOccluded showCaption = isStatusBarVisible && !isKeyguardVisibleAndOccluded if (DesktopExperienceFlags.ENABLE_DESKTOP_WINDOWING_ENTERPRISE_BUGFIX.isTrue() && !taskInfo.isFreeform ) { showCaption = showCaption && !isTaskLocked } } else { // Caption should always be visible in freeform mode. When not in freeform, // align with the status bar except when showing over keyguard (where it should not Loading @@ -627,7 +636,16 @@ class DefaultWindowDecoration @JvmOverloads constructor( // forcibly-shown. It may be that the InsetsState (from which |mIsStatusBarVisible| // is set) still contains an invisible insets source in immersive cases even if the // status bar is shown? taskInfo.isFreeform || (isStatusBarVisible && !isKeyguardVisibleAndOccluded) showCaption = taskInfo.isFreeform || (isStatusBarVisible && !isKeyguardVisibleAndOccluded) if (DesktopExperienceFlags.ENABLE_DESKTOP_WINDOWING_ENTERPRISE_BUGFIX.isTrue() && !taskInfo.isFreeform ) { showCaption = showCaption && !isTaskLocked } } return showCaption } private fun updateDragResizeListenerIfNeeded(containerSurface: SurfaceControl) { Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/LockTaskChangeListener.kt 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.common import android.app.ActivityManager.LOCK_TASK_MODE_NONE import com.android.wm.shell.sysui.ShellInit /** * A component for observing changes to the system's LockTask mode. * * This class listens for changes to LockTaskMode from [TaskStackListenerImpl] and keeps a cache of * the current LockTask mode (LOCK_TASK_MODE_NONE, LOCK_TASK_MODE_LOCKED, LOCK_TASK_MODE_PINNED). * It provides a listener interface for other components to subscribe to these changes, * allowing them to react when a task becomes locked or unlocked. * * To use this class, obtain an instance and register a [LockTaskModeChangedListener] via * the [addListener] method. */ class LockTaskChangeListener( shellInit: ShellInit, private val taskStackListenerImpl: TaskStackListenerImpl, ) : TaskStackListenerCallback { /** Listener for lock task mode changes. */ fun interface LockTaskModeChangedListener { /** Called when the lock task mode changes. */ fun onLockTaskModeChanged(mode: Int) } private var lockTaskMode = LOCK_TASK_MODE_NONE val isTaskLocked get() = lockTaskMode != LOCK_TASK_MODE_NONE private val listeners = linkedSetOf<LockTaskModeChangedListener>() init { shellInit.addInitCallback(::onInit, this) } private fun onInit() { taskStackListenerImpl.addListener(this) } /** Adds a listener for lock task mode changes. */ fun addListener(listener: LockTaskModeChangedListener) { listeners.add(listener) } /** Removes a listener for lock task mode changes. */ fun removeListener(listener: LockTaskModeChangedListener) { listeners.remove(listener) } override fun onLockTaskModeChanged(mode: Int) { lockTaskMode = mode // Notify all registered listeners listeners.forEach { it.onLockTaskModeChanged(lockTaskMode) } } }
libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java +2 −0 Original line number Diff line number Diff line Loading @@ -93,4 +93,6 @@ public interface TaskStackListenerCallback { default void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { } default void onActivityRotation(int displayId) { } default void onLockTaskModeChanged(int mode) { } }
libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java +12 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler. private static final int ON_TASK_DESCRIPTION_CHANGED = 19; private static final int ON_ACTIVITY_ROTATION = 20; private static final int ON_RECENT_TASK_REMOVED_FOR_ADD_TASK = 21; private static final int ON_LOCK_TASK_MODE_CHANGE = 22; /** * List of {@link TaskStackListenerCallback} registered from {@link #addListener}. Loading Loading @@ -137,6 +138,11 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler. mMainHandler.obtainMessage(ON_RECENT_TASK_REMOVED_FOR_ADD_TASK, taskId).sendToTarget(); } @Override public void onLockTaskModeChanged(int mode) { mMainHandler.obtainMessage(ON_LOCK_TASK_MODE_CHANGE, mode, 0 /* unused */).sendToTarget(); } @Override public void onTaskStackChanged() { // Call the task changed callback for the non-ui thread listeners first. Copy to a set Loading Loading @@ -435,6 +441,12 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler. } break; } case ON_LOCK_TASK_MODE_CHANGE: { for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { mTaskStackListeners.get(i).onLockTaskModeChanged(msg.arg1); } break; } } } if (msg.obj instanceof SomeArgs) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +12 −2 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.HomeIntentProvider; import com.android.wm.shell.common.LaunchAdjacentController; import com.android.wm.shell.common.LockTaskChangeListener; import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorController; import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorSurface; import com.android.wm.shell.common.MultiInstanceHelper; Loading Loading @@ -1239,7 +1240,8 @@ public abstract class WMShellModule { DesksOrganizer desksOrganizer, ShellDesktopState shelldesktopState, DesktopConfig desktopConfig, UserProfileContexts userProfileContexts UserProfileContexts userProfileContexts, LockTaskChangeListener lockTaskChangeListener ) { if (!shelldesktopState.canEnterDesktopModeOrShowAppHandle()) { return Optional.empty(); Loading @@ -1258,7 +1260,15 @@ public abstract class WMShellModule { desktopModeUiEventLogger, taskResourceLoader, recentsTransitionHandler, desktopModeCompatPolicy, desktopTilingDecorViewModel, multiDisplayDragMoveIndicatorController, compatUI.orElse(null), desksOrganizer, shelldesktopState, desktopConfig, userProfileContexts)); desksOrganizer, shelldesktopState, desktopConfig, userProfileContexts, lockTaskChangeListener)); } @WMSingleton @Provides static LockTaskChangeListener provideLockTaskChangeListener(ShellInit shellInit, TaskStackListenerImpl taskStackListenerImpl) { return new LockTaskChangeListener(shellInit, taskStackListenerImpl); } @WMSingleton Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DefaultWindowDecoration.kt +23 −5 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser import com.android.wm.shell.apptoweb.AppToWebRepository import com.android.wm.shell.apptoweb.AssistContentRequester import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.LockTaskChangeListener import com.android.wm.shell.common.MultiInstanceHelper import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.common.SyncTransactionQueue Loading Loading @@ -134,6 +135,7 @@ class DefaultWindowDecoration @JvmOverloads constructor( private val windowContainerTransactionSupplier: () -> WindowContainerTransaction = { WindowContainerTransaction() }, surfaceControlSupplier: () -> SurfaceControl = { SurfaceControl() }, private val lockTaskChangeListener: LockTaskChangeListener ) : WindowDecoration2<WindowDecorLinearLayout>( taskInfo, context, Loading Loading @@ -493,7 +495,7 @@ class DefaultWindowDecoration @JvmOverloads constructor( cornerRadiusId = getCornerRadiusId(captionType, shouldIgnoreCornerRadius), borderSettingsId = getBorderSettingsId(captionType, taskInfo, hasGlobalFocus), boxShadowSettingsIds = getShadowSettingsIds(captionType, hasGlobalFocus), isCaptionVisible = shouldShowCaption(taskInfo), isCaptionVisible = shouldShowCaption(taskInfo, lockTaskChangeListener.isTaskLocked), windowDecorConfig = windowDecorConfig, asyncViewHost = asyncViewHost, applyStartTransactionOnDraw = applyStartTransactionOnDraw, Loading Loading @@ -611,13 +613,20 @@ class DefaultWindowDecoration @JvmOverloads constructor( } private fun shouldShowCaption(taskInfo: RunningTaskInfo): Boolean = private fun shouldShowCaption(taskInfo: RunningTaskInfo, isTaskLocked: Boolean): Boolean { var showCaption: Boolean if (DesktopModeFlags.ENABLE_DESKTOP_IMMERSIVE_DRAG_BUGFIX.isTrue && isDragging) { // If the task is being dragged, the caption should not be hidden so that it continues // receiving input true showCaption = true } else if (DesktopModeFlags.ENABLE_FULLY_IMMERSIVE_IN_DESKTOP.isTrue && inFullImmersive) { isStatusBarVisible && !isKeyguardVisibleAndOccluded showCaption = isStatusBarVisible && !isKeyguardVisibleAndOccluded if (DesktopExperienceFlags.ENABLE_DESKTOP_WINDOWING_ENTERPRISE_BUGFIX.isTrue() && !taskInfo.isFreeform ) { showCaption = showCaption && !isTaskLocked } } else { // Caption should always be visible in freeform mode. When not in freeform, // align with the status bar except when showing over keyguard (where it should not Loading @@ -627,7 +636,16 @@ class DefaultWindowDecoration @JvmOverloads constructor( // forcibly-shown. It may be that the InsetsState (from which |mIsStatusBarVisible| // is set) still contains an invisible insets source in immersive cases even if the // status bar is shown? taskInfo.isFreeform || (isStatusBarVisible && !isKeyguardVisibleAndOccluded) showCaption = taskInfo.isFreeform || (isStatusBarVisible && !isKeyguardVisibleAndOccluded) if (DesktopExperienceFlags.ENABLE_DESKTOP_WINDOWING_ENTERPRISE_BUGFIX.isTrue() && !taskInfo.isFreeform ) { showCaption = showCaption && !isTaskLocked } } return showCaption } private fun updateDragResizeListenerIfNeeded(containerSurface: SurfaceControl) { Loading