• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * 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 package com.android.wm.shell.common
17 
18 import android.app.ActivityManager.RunningTaskInfo
19 import android.content.Context
20 import android.graphics.Color
21 import android.graphics.Rect
22 import android.os.Trace
23 import android.view.Display
24 import android.view.SurfaceControl
25 import androidx.compose.material3.dynamicDarkColorScheme
26 import androidx.compose.material3.dynamicLightColorScheme
27 import androidx.compose.ui.graphics.toArgb
28 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
29 import com.android.wm.shell.windowdecor.common.DecorThemeUtil
30 import com.android.wm.shell.windowdecor.common.Theme
31 
32 /**
33  * Represents the indicator surface that visualizes the current position of a dragged window during
34  * a multi-display drag operation.
35  *
36  * This class manages the creation, display, and manipulation of the [SurfaceControl]s that act as a
37  * visual indicator, providing feedback to the user about the dragged window's location.
38  */
39 class MultiDisplayDragMoveIndicatorSurface(
40     context: Context,
41     taskInfo: RunningTaskInfo,
42     display: Display,
43     surfaceControlBuilderFactory: Factory.SurfaceControlBuilderFactory,
44 ) {
45     private var isVisible = false
46 
47     // A container surface to host the veil background
48     private var veilSurface: SurfaceControl? = null
49 
50     private val decorThemeUtil = DecorThemeUtil(context)
51     private val lightColors = dynamicLightColorScheme(context)
52     private val darkColors = dynamicDarkColorScheme(context)
53 
54     init {
55         Trace.beginSection("DragIndicatorSurface#init")
56 
57         val displayId = display.displayId
58         veilSurface =
59             surfaceControlBuilderFactory
60                 .create("Drag indicator veil of Task=${taskInfo.taskId} Display=$displayId")
61                 .setColorLayer()
62                 .setCallsite("DragIndicatorSurface#init")
63                 .setHidden(true)
64                 .build()
65 
66         // TODO: b/383069173 - Add icon for the surface.
67 
68         Trace.endSection()
69     }
70 
71     /**
72      * Disposes the indicator surface using the provided [transaction].
73      */
74     fun disposeSurface(transaction: SurfaceControl.Transaction) {
75         veilSurface?.let { veil -> transaction.remove(veil) }
76         veilSurface = null
77     }
78 
79     /**
80      * Shows the indicator surface at [bounds] on the specified display ([displayId]),
81      * visualizing the drag of the [taskInfo]. The indicator surface is shown using [transaction],
82      * and the [rootTaskDisplayAreaOrganizer] is used to reparent the surfaces.
83      */
84     fun show(
85         transaction: SurfaceControl.Transaction,
86         taskInfo: RunningTaskInfo,
87         rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
88         displayId: Int,
89         bounds: Rect,
90     ) {
91         val backgroundColor =
92             when (decorThemeUtil.getAppTheme(taskInfo)) {
93                 Theme.LIGHT -> lightColors.surfaceContainer
94                 Theme.DARK -> darkColors.surfaceContainer
95             }
96         val veil = veilSurface ?: return
97         isVisible = true
98 
99         rootTaskDisplayAreaOrganizer.reparentToDisplayArea(displayId, veil, transaction)
100         relayout(bounds, transaction, shouldBeVisible = true)
101         transaction.show(veil).setColor(veil, Color.valueOf(backgroundColor.toArgb()).components)
102         transaction.apply()
103     }
104 
105     /**
106      * Repositions and resizes the indicator surface based on [bounds] using [transaction]. The
107      * [shouldBeVisible] flag indicates whether the indicator is within the display after relayout.
108      */
109     fun relayout(bounds: Rect, transaction: SurfaceControl.Transaction, shouldBeVisible: Boolean) {
110         if (!isVisible && !shouldBeVisible) {
111             // No need to relayout if the surface is already invisible and should not be visible.
112             return
113         }
114         isVisible = shouldBeVisible
115         val veil = veilSurface ?: return
116         transaction.setCrop(veil, bounds)
117     }
118 
119     /**
120      * Factory for creating [MultiDisplayDragMoveIndicatorSurface] instances with the [context].
121      */
122     class Factory(private val context: Context) {
123         private val surfaceControlBuilderFactory: SurfaceControlBuilderFactory =
124             object : SurfaceControlBuilderFactory {}
125 
126         /**
127          * Creates a new [MultiDisplayDragMoveIndicatorSurface] instance to visualize the drag
128          * operation of the [taskInfo] on the given [display].
129          */
130         fun create(
131             taskInfo: RunningTaskInfo,
132             display: Display,
133         ) = MultiDisplayDragMoveIndicatorSurface(
134             context,
135             taskInfo,
136             display,
137             surfaceControlBuilderFactory,
138         )
139 
140         /**
141          * Interface for creating [SurfaceControl.Builder] instances.
142          *
143          * This provides an abstraction over [SurfaceControl.Builder] creation for testing purposes.
144          */
145         interface SurfaceControlBuilderFactory {
146             fun create(name: String): SurfaceControl.Builder {
147                 return SurfaceControl.Builder().setName(name)
148             }
149         }
150     }
151 }
152