• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.wm.shell.windowdecor.common
18 
19 import android.app.ActivityManager
20 import android.app.WindowConfiguration
21 import android.content.Context
22 import android.view.WindowManager
23 import android.window.DesktopExperienceFlags.ENABLE_BUG_FIXES_FOR_SECONDARY_DISPLAY
24 import com.android.wm.shell.common.DisplayController
25 import com.android.wm.shell.desktopmode.DesktopWallpaperActivity.Companion.isWallpaperTask
26 import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper
27 import com.android.wm.shell.shared.desktopmode.DesktopModeCompatPolicy
28 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
29 import com.android.wm.shell.splitscreen.SplitScreenController
30 
31 /**
32  * Resolves whether, given a task and its associated display that it is currently on, to show the
33  * app handle/header or not.
34  */
35 class AppHandleAndHeaderVisibilityHelper (
36     private val context: Context,
37     private val displayController: DisplayController,
38     private val desktopModeCompatPolicy: DesktopModeCompatPolicy
39 ) {
40     var splitScreenController: SplitScreenController? = null
41 
42     /**
43      * Returns, given a task's attribute and its display attribute, whether the app
44      * handle/header should show or not for this task.
45      */
shouldShowAppHandleOrHeadernull46     fun shouldShowAppHandleOrHeader(taskInfo: ActivityManager.RunningTaskInfo): Boolean {
47         if (!ENABLE_BUG_FIXES_FOR_SECONDARY_DISPLAY.isTrue) {
48             return allowedForTask(taskInfo)
49         }
50         return allowedForTask(taskInfo) && allowedForDisplay(taskInfo.displayId)
51     }
52 
allowedForTasknull53     private fun allowedForTask(taskInfo: ActivityManager.RunningTaskInfo): Boolean {
54         // TODO (b/382023296): Remove once we no longer rely on
55         //  Flags.enableBugFixesForSecondaryDisplay as it is taken care of in #allowedForDisplay
56         val display = displayController.getDisplay(taskInfo.displayId)
57         if (display == null) {
58             // If DisplayController doesn't have it tracked, it could be a private/managed display.
59             return false
60         }
61         if (taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM) return true
62         if (splitScreenController?.isTaskRootOrStageRoot(taskInfo.taskId) == true) {
63             return false
64         }
65 
66         if (desktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing(taskInfo)) {
67             return false
68         }
69 
70         // TODO (b/382023296): Remove once we no longer rely on
71         //  Flags.enableBugFixesForSecondaryDisplay as it is taken care of in #allowedForDisplay
72         val isOnLargeScreen =
73             display.minSizeDimensionDp >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
74         if (!DesktopModeStatus.canEnterDesktopMode(context)
75             && DesktopModeStatus.overridesShowAppHandle(context)
76             && !isOnLargeScreen
77         ) {
78             // Devices with multiple screens may enable the app handle but it should not show on
79             // small screens
80             return false
81         }
82         if (BubbleAnythingFlagHelper.enableBubbleToFullscreen()
83             && !DesktopModeStatus.isDesktopModeSupportedOnDisplay(context, display)
84         ) {
85             // TODO(b/388853233): enable handles for split tasks once drag to bubble is enabled
86             if (taskInfo.windowingMode != WindowConfiguration.WINDOWING_MODE_FULLSCREEN) {
87                 return false
88             }
89         }
90         return DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context)
91                 && !isWallpaperTask(taskInfo)
92                 && taskInfo.windowingMode != WindowConfiguration.WINDOWING_MODE_PINNED
93                 && taskInfo.activityType == WindowConfiguration.ACTIVITY_TYPE_STANDARD
94                 && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop
95     }
96 
allowedForDisplaynull97     private fun allowedForDisplay(displayId: Int): Boolean {
98         // If DisplayController doesn't have it tracked, it could be a private/managed display.
99         val display = displayController.getDisplay(displayId)
100         if (display == null) return false
101 
102         if (DesktopModeStatus.isDesktopModeSupportedOnDisplay(context, display)) {
103             return true
104         }
105         // If on default display and on Large Screen (unfolded), show app handle
106         return DesktopModeStatus.overridesShowAppHandle(context)
107                 && display.minSizeDimensionDp >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
108     }
109 }