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

Commit d3d17a89 authored by Thales Lima's avatar Thales Lima
Browse files

Hide the Task handle when in Lock Task Mode

If we allow apps to use the handle they can try to use split screen or send the task to Desktop Mode. A new listener was created for LockTask mode so Shell doesn't need to call ATMS and do a Binder call.

Fix: 402431290
Test: LockTaskChangeListenerTest, DesktopModeWindowDecorationTests, TaskStackListenerImplTest
Test: Start Lock Task mode using TestDPC and open a locked app (check bug for steps)
Flag: com.android.window.flags.enable_desktop_windowing_enterprise_bugfix
Change-Id: Ibf4a3a4b50698030d1eb9488f33008b69cc7a938
parent 45a5ba0b
Loading
Loading
Loading
Loading
+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) }
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -93,4 +93,6 @@ public interface TaskStackListenerCallback {
    default void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { }

    default void onActivityRotation(int displayId) { }

    default void onLockTaskModeChanged(int mode) { }
}
+12 −0
Original line number Diff line number Diff line
@@ -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}.
@@ -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
@@ -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) {
+12 −2
Original line number Diff line number Diff line
@@ -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;
@@ -1236,7 +1237,8 @@ public abstract class WMShellModule {
            DesksOrganizer desksOrganizer,
            ShellDesktopState shelldesktopState,
            DesktopConfig desktopConfig,
            UserProfileContexts userProfileContexts
            UserProfileContexts userProfileContexts,
            LockTaskChangeListener lockTaskChangeListener
    ) {
        if (!shelldesktopState.canEnterDesktopModeOrShowAppHandle()) {
            return Optional.empty();
@@ -1255,7 +1257,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
+23 −5
Original line number Diff line number Diff line
@@ -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
@@ -134,6 +135,7 @@ class DefaultWindowDecoration @JvmOverloads constructor(
    private val windowContainerTransactionSupplier: () -> WindowContainerTransaction =
        { WindowContainerTransaction() },
    surfaceControlSupplier: () -> SurfaceControl = { SurfaceControl() },
    private val lockTaskChangeListener: LockTaskChangeListener
) : WindowDecoration2<WindowDecorLinearLayout>(
    taskInfo,
    context,
@@ -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,
@@ -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
@@ -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