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

Commit 43843170 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Report app handle bounds to status bar" into main

parents d25e2af1 59610a4d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ public enum DesktopExperienceFlags {
    ENABLE_ACTIVITY_EMBEDDING_SUPPORT_FOR_CONNECTED_DISPLAYS(
            Flags::enableActivityEmbeddingSupportForConnectedDisplays, true,
            Flags.FLAG_ENABLE_ACTIVITY_EMBEDDING_SUPPORT_FOR_CONNECTED_DISPLAYS),
    ENABLE_APP_HANDLE_POSITION_REPORTING(Flags::enableAppHandlePositionReporting, false,
            Flags.FLAG_ENABLE_APP_HANDLE_POSITION_REPORTING),
    ENABLE_BLOCK_NON_DESKTOP_DISPLAY_WINDOW_DRAG_BUGFIX(
            Flags::enableBlockNonDesktopDisplayWindowDragBugfix, false,
            Flags.FLAG_ENABLE_BLOCK_NON_DESKTOP_DISPLAY_WINDOW_DRAG_BUGFIX),
+10 −0
Original line number Diff line number Diff line
@@ -1261,6 +1261,16 @@ flag {
    }
}

flag {
    name: "enable_app_handle_position_reporting"
    namespace: "lse_desktop_experience"
    description: "Report app handle position to the SysUi."
    bug: "412444130"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "enable_desktop_app_launch_bugfix"
    namespace: "lse_desktop_experience"
+16 −14
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator;
import com.android.wm.shell.desktopmode.SpringDragToDesktopTransitionHandler;
import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler;
import com.android.wm.shell.desktopmode.VisualIndicatorUpdateScheduler;
import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
import com.android.wm.shell.desktopmode.WindowDecorCaptionRepository;
import com.android.wm.shell.desktopmode.compatui.SystemModalsTransitionHandler;
import com.android.wm.shell.desktopmode.desktopfirst.DesktopDisplayModeController;
import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider;
@@ -1154,7 +1154,7 @@ public abstract class WMShellModule {
            AppHandleEducationController appHandleEducationController,
            AppToWebEducationController appToWebEducationController,
            AppHandleAndHeaderVisibilityHelper appHandleAndHeaderVisibilityHelper,
            WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
            WindowDecorCaptionRepository windowDecorCaptionRepository,
            Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
            FocusTransitionObserver focusTransitionObserver,
            DesktopModeEventLogger desktopModeEventLogger,
@@ -1167,8 +1167,7 @@ public abstract class WMShellModule {
            Optional<CompatUIHandler> compatUI,
            DesksOrganizer desksOrganizer,
            DesktopState desktopState,
            DesktopConfig desktopConfig,
            AppHandleNotifier appHandleNotifier
            DesktopConfig desktopConfig
    ) {
        if (!desktopState.canEnterDesktopModeOrShowAppHandle()) {
            return Optional.empty();
@@ -1182,12 +1181,12 @@ public abstract class WMShellModule {
                rootTaskDisplayAreaOrganizer, interactionJankMonitor, genericLinksParser,
                assistContentRequester, windowDecorViewHostSupplier, multiInstanceHelper,
                desktopTasksLimiter, appHandleEducationController, appToWebEducationController,
                appHandleAndHeaderVisibilityHelper, windowDecorCaptionHandleRepository,
                appHandleAndHeaderVisibilityHelper, windowDecorCaptionRepository,
                activityOrientationChangeHandler, focusTransitionObserver, desktopModeEventLogger,
                desktopModeUiEventLogger, taskResourceLoader, recentsTransitionHandler,
                desktopModeCompatPolicy, desktopTilingDecorViewModel,
                multiDisplayDragMoveIndicatorController, compatUI.orElse(null),
                desksOrganizer, desktopState, desktopConfig, appHandleNotifier));
                desksOrganizer, desktopState, desktopConfig));
    }

    @WMSingleton
@@ -1525,8 +1524,11 @@ public abstract class WMShellModule {
    @WMSingleton
    @Provides
    static AppHandleNotifier provideAppHandleNotifier(
            @ShellMainThread ShellExecutor shellExecutor) {
        return new AppHandleNotifier(shellExecutor);
            @ShellMainThread ShellExecutor shellExecutor,
            WindowDecorCaptionRepository windowDecorCaptionRepository,
            @ShellMainThread CoroutineScope mainScope) {
        return new AppHandleNotifier(
                shellExecutor, windowDecorCaptionRepository, mainScope);
    }

    @WMSingleton
@@ -1546,8 +1548,8 @@ public abstract class WMShellModule {

    @WMSingleton
    @Provides
    static WindowDecorCaptionHandleRepository provideAppHandleRepository() {
        return new WindowDecorCaptionHandleRepository();
    static WindowDecorCaptionRepository provideAppHandleRepository() {
        return new WindowDecorCaptionRepository();
    }

    @WMSingleton
@@ -1582,7 +1584,7 @@ public abstract class WMShellModule {
            Context context,
            AppHandleEducationFilter appHandleEducationFilter,
            AppHandleEducationDatastoreRepository appHandleEducationDatastoreRepository,
            WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
            WindowDecorCaptionRepository windowDecorCaptionRepository,
            DesktopWindowingEducationTooltipController desktopWindowingEducationTooltipController,
            @ShellMainThread CoroutineScope applicationScope,
            @ShellBackgroundThread MainCoroutineDispatcher backgroundDispatcher,
@@ -1592,7 +1594,7 @@ public abstract class WMShellModule {
                context,
                appHandleEducationFilter,
                appHandleEducationDatastoreRepository,
                windowDecorCaptionHandleRepository,
                windowDecorCaptionRepository,
                desktopWindowingEducationTooltipController,
                applicationScope,
                backgroundDispatcher,
@@ -1622,13 +1624,13 @@ public abstract class WMShellModule {
            Context context,
            AppToWebEducationFilter appToWebEducationFilter,
            AppToWebEducationDatastoreRepository appToWebEducationDatastoreRepository,
            WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
            WindowDecorCaptionRepository windowDecorCaptionRepository,
            DesktopWindowingEducationPromoController desktopWindowingEducationPromoController,
            @ShellMainThread CoroutineScope applicationScope,
            @ShellBackgroundThread MainCoroutineDispatcher backgroundDispatcher,
            DesktopState desktopState) {
        return new AppToWebEducationController(context, appToWebEducationFilter,
                appToWebEducationDatastoreRepository, windowDecorCaptionHandleRepository,
                appToWebEducationDatastoreRepository, windowDecorCaptionRepository,
                desktopWindowingEducationPromoController, applicationScope,
                backgroundDispatcher, desktopState);
    }
+16 −4
Original line number Diff line number Diff line
@@ -21,13 +21,14 @@ import android.graphics.Rect
import com.android.wm.shell.desktopmode.CaptionState.AppHandle
import com.android.wm.shell.desktopmode.CaptionState.AppHeader
import com.android.wm.shell.desktopmode.CaptionState.NoCaption
import com.android.wm.shell.windowdecor.viewholder.AppHandleIdentifier
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

/** Repository to observe caption state. */
class WindowDecorCaptionHandleRepository {
    private val _captionStateFlow = MutableStateFlow<CaptionState>(CaptionState.NoCaption)
class WindowDecorCaptionRepository {
    private val _captionStateFlow = MutableStateFlow<CaptionState>(NoCaption())
    /** Observer for app handle state changes. */
    val captionStateFlow: StateFlow<CaptionState> = _captionStateFlow
    private val _appToWebUsageFlow = MutableSharedFlow<Unit>()
@@ -51,14 +52,18 @@ class WindowDecorCaptionHandleRepository {
 * It can be one of three options:
 * * [AppHandle]: Indicating that there is at least one visible app handle on the screen.
 * * [AppHeader]: Indicating that there is at least one visible app chip on the screen.
 * * [NoCaption]: Signifying that no caption handle is currently visible on the device.
 * * [NoCaption]: Signifying that no caption handle visible for the given task.
 */
sealed class CaptionState {
    abstract val isFocused: Boolean

    data class AppHandle(
        val runningTaskInfo: RunningTaskInfo,
        val isHandleMenuExpanded: Boolean,
        val globalAppHandleBounds: Rect,
        val isCapturedLinkAvailable: Boolean,
        val appHandleIdentifier: AppHandleIdentifier,
        override val isFocused: Boolean,
    ) : CaptionState()

    data class AppHeader(
@@ -66,7 +71,14 @@ sealed class CaptionState {
        val isHeaderMenuExpanded: Boolean,
        val globalAppChipBounds: Rect,
        val isCapturedLinkAvailable: Boolean,
        override val isFocused: Boolean,
    ) : CaptionState()

    data object NoCaption : CaptionState()
    data class NoCaption(val taskId: Int = INVALID_TASK_ID) : CaptionState() {
        override val isFocused = false
    }

    private companion object {
        private const val INVALID_TASK_ID = -1
    }
}
+18 −8
Original line number Diff line number Diff line
@@ -23,16 +23,16 @@ import android.content.res.Resources
import android.graphics.Point
import android.os.SystemProperties
import android.view.View.LAYOUT_DIRECTION_RTL
import android.window.DesktopExperienceFlags
import com.android.window.flags.Flags
import com.android.wm.shell.R
import com.android.wm.shell.desktopmode.CaptionState
import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger
import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum
import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository
import com.android.wm.shell.desktopmode.WindowDecorCaptionRepository
import com.android.wm.shell.desktopmode.education.data.AppHandleEducationDatastoreRepository
import com.android.wm.shell.shared.annotations.ShellBackgroundThread
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopMode
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
import com.android.wm.shell.shared.desktopmode.DesktopState
import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController
@@ -61,7 +61,7 @@ class AppHandleEducationController(
    private val context: Context,
    private val appHandleEducationFilter: AppHandleEducationFilter,
    private val appHandleEducationDatastoreRepository: AppHandleEducationDatastoreRepository,
    private val windowDecorCaptionHandleRepository: WindowDecorCaptionHandleRepository,
    private val windowDecorCaptionRepository: WindowDecorCaptionRepository,
    private val windowingEducationViewController: DesktopWindowingEducationTooltipController,
    @ShellMainThread private val applicationCoroutineScope: CoroutineScope,
    @ShellBackgroundThread private val backgroundDispatcher: MainCoroutineDispatcher,
@@ -81,11 +81,12 @@ class AppHandleEducationController(
            // encourage users to open the app handle menu.
            applicationCoroutineScope.launch {
                if (isAppHandleHintViewed()) return@launch
                windowDecorCaptionHandleRepository.captionStateFlow
                windowDecorCaptionRepository.captionStateFlow
                    .debounce(APP_HANDLE_EDUCATION_DELAY_MILLIS)
                    .filter { captionState ->
                        captionState is CaptionState.AppHandle &&
                            !captionState.isHandleMenuExpanded &&
                            isCaptionFocused(captionState) &&
                            !isAppHandleHintViewed() &&
                            appHandleEducationFilter.shouldShowDesktopModeEducation(captionState)
                    }
@@ -104,11 +105,12 @@ class AppHandleEducationController(
            // encourage users to enter desktop mode.
            applicationCoroutineScope.launch {
                if (isEnterDesktopModeHintViewed()) return@launch
                windowDecorCaptionHandleRepository.captionStateFlow
                windowDecorCaptionRepository.captionStateFlow
                    .debounce(ENTER_DESKTOP_MODE_EDUCATION_DELAY_MILLIS)
                    .filter { captionState ->
                        captionState is CaptionState.AppHandle &&
                            captionState.isHandleMenuExpanded &&
                            isCaptionFocused(captionState) &&
                            !isEnterDesktopModeHintViewed() &&
                            appHandleEducationFilter.shouldShowDesktopModeEducation(captionState)
                    }
@@ -127,11 +129,12 @@ class AppHandleEducationController(
            // to let users know how to exit desktop mode.
            applicationCoroutineScope.launch {
                if (isExitDesktopModeHintViewed()) return@launch
                windowDecorCaptionHandleRepository.captionStateFlow
                windowDecorCaptionRepository.captionStateFlow
                    .debounce(APP_HANDLE_EDUCATION_DELAY_MILLIS)
                    .filter { captionState ->
                        captionState is CaptionState.AppHeader &&
                            !captionState.isHeaderMenuExpanded &&
                            isCaptionFocused(captionState) &&
                            !isExitDesktopModeHintViewed() &&
                            appHandleEducationFilter.shouldShowDesktopModeEducation(captionState)
                    }
@@ -156,9 +159,9 @@ class AppHandleEducationController(
                        isExitDesktopModeHintViewed()
                )
                    return@launch
                windowDecorCaptionHandleRepository.captionStateFlow
                windowDecorCaptionRepository.captionStateFlow
                    .filter { captionState ->
                        captionState is CaptionState.NoCaption &&
                        !isCaptionFocused(captionState) &&
                            !isAppHandleHintViewed() &&
                            !isEnterDesktopModeHintViewed() &&
                            !isExitDesktopModeHintViewed()
@@ -174,6 +177,13 @@ class AppHandleEducationController(
            block()
    }

    private fun isCaptionFocused(captionState: CaptionState) =
        if (!DesktopExperienceFlags.ENABLE_APP_HANDLE_POSITION_REPORTING.isTrue) {
            captionState !is CaptionState.NoCaption
        } else {
            captionState.isFocused
        }

    private fun showEducation(captionState: CaptionState) {
        val appHandleBounds = (captionState as CaptionState.AppHandle).globalAppHandleBounds
        val taskInfo = captionState.runningTaskInfo
Loading