1 /*
2  * Copyright (C) 2024 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 package com.android.wm.shell.desktopmode.common
17 
18 import android.graphics.Rect
19 import com.android.internal.jank.Cuj
20 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod
21 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
22 import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum
23 import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction.AmbiguousSource
24 import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction.Source
25 
26 /** Represents a user interaction to toggle a desktop task's size from to maximize or vice versa. */
27 data class ToggleTaskSizeInteraction
28 @JvmOverloads
29 constructor(
30     val direction: Direction,
31     val source: Source,
32     val inputMethod: InputMethod,
33     val animationStartBounds: Rect? = null,
34 ) {
35     constructor(
36         isMaximized: Boolean,
37         source: Source,
38         inputMethod: InputMethod,
39     ) : this(
40         direction = if (isMaximized) Direction.RESTORE else Direction.MAXIMIZE,
41         source = source,
42         inputMethod = inputMethod,
43     )
44 
45     val jankTag: String? =
46         when (source) {
47             Source.HEADER_BUTTON_TO_MAXIMIZE -> "caption_bar_button"
48             Source.HEADER_BUTTON_TO_RESTORE -> "caption_bar_button"
49             Source.KEYBOARD_SHORTCUT -> null
50             Source.HEADER_DRAG_TO_TOP -> null
51             Source.MAXIMIZE_MENU_TO_MAXIMIZE -> "maximize_menu"
52             Source.MAXIMIZE_MENU_TO_RESTORE -> "maximize_menu"
53             Source.DOUBLE_TAP_TO_MAXIMIZE -> "double_tap"
54             Source.DOUBLE_TAP_TO_RESTORE -> "double_tap"
55         }
56     val uiEvent: DesktopUiEventEnum? =
57         when (source) {
58             Source.HEADER_BUTTON_TO_MAXIMIZE ->
59                 DesktopUiEventEnum.DESKTOP_WINDOW_MAXIMIZE_BUTTON_TAP
60             Source.HEADER_BUTTON_TO_RESTORE -> DesktopUiEventEnum.DESKTOP_WINDOW_RESTORE_BUTTON_TAP
61             Source.KEYBOARD_SHORTCUT -> null
62             Source.HEADER_DRAG_TO_TOP -> null
63             Source.MAXIMIZE_MENU_TO_MAXIMIZE -> {
64                 DesktopUiEventEnum.DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_MAXIMIZE
65             }
66             Source.MAXIMIZE_MENU_TO_RESTORE -> {
67                 DesktopUiEventEnum.DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_RESTORE
68             }
69             Source.DOUBLE_TAP_TO_MAXIMIZE -> {
70                 DesktopUiEventEnum.DESKTOP_WINDOW_HEADER_DOUBLE_TAP_TO_MAXIMIZE
71             }
72             Source.DOUBLE_TAP_TO_RESTORE -> {
73                 DesktopUiEventEnum.DESKTOP_WINDOW_HEADER_DOUBLE_TAP_TO_RESTORE
74             }
75         }
76     val resizeTrigger =
77         when (source) {
78             Source.HEADER_BUTTON_TO_MAXIMIZE -> ResizeTrigger.MAXIMIZE_BUTTON
79             Source.HEADER_BUTTON_TO_RESTORE -> ResizeTrigger.MAXIMIZE_BUTTON
80             Source.KEYBOARD_SHORTCUT -> ResizeTrigger.UNKNOWN_RESIZE_TRIGGER
81             Source.HEADER_DRAG_TO_TOP -> ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER
82             Source.MAXIMIZE_MENU_TO_MAXIMIZE -> ResizeTrigger.MAXIMIZE_MENU
83             Source.MAXIMIZE_MENU_TO_RESTORE -> ResizeTrigger.MAXIMIZE_MENU
84             Source.DOUBLE_TAP_TO_MAXIMIZE -> ResizeTrigger.DOUBLE_TAP_APP_HEADER
85             Source.DOUBLE_TAP_TO_RESTORE -> ResizeTrigger.DOUBLE_TAP_APP_HEADER
86         }
87     val cujTracing: Int? =
88         when (source) {
89             Source.HEADER_BUTTON_TO_MAXIMIZE -> Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW
90             Source.HEADER_BUTTON_TO_RESTORE -> Cuj.CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW
91             Source.KEYBOARD_SHORTCUT -> null
92             Source.HEADER_DRAG_TO_TOP -> null
93             Source.MAXIMIZE_MENU_TO_MAXIMIZE -> null
94             Source.MAXIMIZE_MENU_TO_RESTORE -> null
95             Source.DOUBLE_TAP_TO_MAXIMIZE -> null
96             Source.DOUBLE_TAP_TO_RESTORE -> null
97         }
98 
99     /** The direction to which the task is being resized. */
100     enum class Direction {
101         MAXIMIZE,
102         RESTORE,
103     }
104 
105     /** The user interaction source. */
106     enum class Source {
107         HEADER_BUTTON_TO_MAXIMIZE,
108         HEADER_BUTTON_TO_RESTORE,
109         KEYBOARD_SHORTCUT,
110         HEADER_DRAG_TO_TOP,
111         MAXIMIZE_MENU_TO_MAXIMIZE,
112         MAXIMIZE_MENU_TO_RESTORE,
113         DOUBLE_TAP_TO_MAXIMIZE,
114         DOUBLE_TAP_TO_RESTORE,
115     }
116 
117     /**
118      * Temporary sources for interactions that should be broken into more specific sources, for
119      * example, the header button click should use [Source.HEADER_BUTTON_TO_MAXIMIZE] and
120      * [Source.HEADER_BUTTON_TO_RESTORE].
121      *
122      * TODO: b/341320112 - break these out into different [Source]s.
123      */
124     enum class AmbiguousSource {
125         HEADER_BUTTON,
126         MAXIMIZE_MENU,
127         DOUBLE_TAP,
128     }
129 }
130 
131 /** Returns the non-ambiguous [Source] based on the maximized state of the task. */
AmbiguousSourcenull132 fun AmbiguousSource.toSource(isMaximized: Boolean): Source {
133     return when (this) {
134         AmbiguousSource.HEADER_BUTTON ->
135             if (isMaximized) {
136                 Source.HEADER_BUTTON_TO_RESTORE
137             } else {
138                 Source.HEADER_BUTTON_TO_MAXIMIZE
139             }
140         AmbiguousSource.MAXIMIZE_MENU ->
141             if (isMaximized) {
142                 Source.MAXIMIZE_MENU_TO_RESTORE
143             } else {
144                 Source.MAXIMIZE_MENU_TO_MAXIMIZE
145             }
146         AmbiguousSource.DOUBLE_TAP ->
147             if (isMaximized) {
148                 Source.DOUBLE_TAP_TO_RESTORE
149             } else {
150                 Source.DOUBLE_TAP_TO_MAXIMIZE
151             }
152     }
153 }
154