• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.launcher3.taskbar
17 
18 import android.animation.AnimatorSet
19 import android.graphics.Canvas
20 import android.view.View
21 import android.view.ViewTreeObserver
22 import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION
23 import android.view.WindowManager
24 import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
25 import com.android.launcher3.views.BaseDragLayer
26 import com.android.systemui.animation.ViewRootSync
27 import java.io.PrintWriter
28 
29 private const val TASKBAR_ICONS_FADE_DURATION = 300L
30 private const val STASHED_HANDLE_FADE_DURATION = 180L
31 private const val TEMP_BACKGROUND_WINDOW_TITLE = "VoiceInteractionTaskbarBackground"
32 
33 /**
34  * Controls Taskbar behavior while Voice Interaction Window (assistant) is showing. Specifically:
35  * - We always hide the taskbar icons or stashed handle, whichever is currently showing.
36  * - For persistent taskbar, we also move the taskbar background to a new window/layer
37  *   (TYPE_APPLICATION_OVERLAY) which is behind the assistant.
38  * - For transient taskbar, we hide the real taskbar background (if it's showing).
39  */
40 class VoiceInteractionWindowController(val context: TaskbarActivityContext) :
41     TaskbarControllers.LoggableTaskbarController, TaskbarControllers.BackgroundRendererController {
42 
43     private val isSeparateBackgroundEnabled = !context.isTransientTaskbar && !context.isPhoneMode
44     private val taskbarBackgroundRenderer = TaskbarBackgroundRenderer(context)
45     private val nonTouchableInsetsComputer =
<lambda>null46         ViewTreeObserver.OnComputeInternalInsetsListener {
47             it.touchableRegion.setEmpty()
48             it.setTouchableInsets(TOUCHABLE_INSETS_REGION)
49         }
50 
51     // Initialized in init.
52     private lateinit var controllers: TaskbarControllers
53     // Only initialized if isSeparateBackgroundEnabled
54     private var separateWindowForTaskbarBackground: BaseDragLayer<TaskbarActivityContext>? = null
55     private var separateWindowLayoutParams: WindowManager.LayoutParams? = null
56 
57     private var isVoiceInteractionWindowVisible: Boolean = false
58     private var pendingAttachedToWindowListener: View.OnAttachStateChangeListener? = null
59 
initnull60     fun init(controllers: TaskbarControllers) {
61         this.controllers = controllers
62 
63         if (!isSeparateBackgroundEnabled) {
64             return
65         }
66 
67         separateWindowForTaskbarBackground =
68             object : BaseDragLayer<TaskbarActivityContext>(context, null, 0) {
69                 override fun recreateControllers() {
70                     mControllers = emptyArray()
71                 }
72 
73                 override fun draw(canvas: Canvas) {
74                     super.draw(canvas)
75                     if (controllers.taskbarStashController.isTaskbarVisibleAndNotStashing) {
76                         taskbarBackgroundRenderer.draw(canvas)
77                     }
78                 }
79 
80                 override fun onAttachedToWindow() {
81                     super.onAttachedToWindow()
82                     viewTreeObserver.addOnComputeInternalInsetsListener(nonTouchableInsetsComputer)
83                 }
84 
85                 override fun onDetachedFromWindow() {
86                     super.onDetachedFromWindow()
87                     viewTreeObserver.removeOnComputeInternalInsetsListener(
88                         nonTouchableInsetsComputer
89                     )
90                 }
91             }
92         separateWindowForTaskbarBackground?.recreateControllers()
93         separateWindowForTaskbarBackground?.setWillNotDraw(false)
94 
95         separateWindowLayoutParams =
96             context.createDefaultWindowLayoutParams(
97                 TYPE_APPLICATION_OVERLAY,
98                 TEMP_BACKGROUND_WINDOW_TITLE,
99             )
100         separateWindowLayoutParams?.isSystemApplicationOverlay = true
101     }
102 
onDestroynull103     fun onDestroy() {
104         setIsVoiceInteractionWindowVisible(visible = false, skipAnim = true)
105         separateWindowForTaskbarBackground?.removeOnAttachStateChangeListener(
106             pendingAttachedToWindowListener
107         )
108     }
109 
setIsVoiceInteractionWindowVisiblenull110     fun setIsVoiceInteractionWindowVisible(visible: Boolean, skipAnim: Boolean) {
111         if (isVoiceInteractionWindowVisible == visible || context.isPhoneMode) {
112             return
113         }
114         isVoiceInteractionWindowVisible = visible
115 
116         // Fade out taskbar icons and stashed handle.
117         val taskbarIconAlpha = if (isVoiceInteractionWindowVisible) 0f else 1f
118         val fadeTaskbarIcons =
119             controllers.taskbarViewController.taskbarIconAlpha
120                 .get(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
121                 .animateToValue(taskbarIconAlpha)
122                 .setDuration(TASKBAR_ICONS_FADE_DURATION)
123         val fadeStashedHandle =
124             controllers.stashedHandleViewController.stashedHandleAlpha
125                 .get(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
126                 .animateToValue(taskbarIconAlpha)
127                 .setDuration(STASHED_HANDLE_FADE_DURATION)
128         val animSet = AnimatorSet()
129         animSet.play(fadeTaskbarIcons)
130         animSet.play(fadeStashedHandle)
131         if (!isSeparateBackgroundEnabled) {
132             val fadeTaskbarBackground =
133                 controllers.taskbarDragLayerController.assistantBgTaskbar
134                     .animateToValue(taskbarIconAlpha)
135                     .setDuration(TASKBAR_ICONS_FADE_DURATION)
136             animSet.play(fadeTaskbarBackground)
137         }
138         animSet.start()
139         if (skipAnim) {
140             animSet.end()
141         }
142 
143         if (isSeparateBackgroundEnabled) {
144             moveTaskbarBackgroundToAppropriateLayer(skipAnim)
145         }
146     }
147 
148     /**
149      * Either:
150      *
151      * Hides the TaskbarDragLayer background and creates a new window to draw just that background.
152      *
153      * OR
154      *
155      * Removes the temporary window and show the TaskbarDragLayer background again.
156      */
moveTaskbarBackgroundToAppropriateLayernull157     private fun moveTaskbarBackgroundToAppropriateLayer(skipAnim: Boolean) {
158         val moveToLowerLayer = isVoiceInteractionWindowVisible
159         val onWindowsSynchronized =
160             if (moveToLowerLayer) {
161                 // First add the temporary window, then hide the overlapping taskbar background.
162                 context.addWindowView(
163                     separateWindowForTaskbarBackground,
164                     separateWindowLayoutParams,
165                 );
166                 { controllers.taskbarDragLayerController.setIsBackgroundDrawnElsewhere(true) }
167             } else {
168                 // First reapply the original taskbar background, then remove the temporary window.
169                 controllers.taskbarDragLayerController.setIsBackgroundDrawnElsewhere(false);
170                 { context.removeWindowView(separateWindowForTaskbarBackground) }
171             }
172 
173         if (skipAnim) {
174             onWindowsSynchronized()
175         } else {
176             separateWindowForTaskbarBackground?.runWhenAttachedToWindow {
177                 ViewRootSync.synchronizeNextDraw(
178                     separateWindowForTaskbarBackground!!,
179                     context.dragLayer,
180                     onWindowsSynchronized,
181                 )
182             }
183         }
184     }
185 
runWhenAttachedToWindownull186     private fun View.runWhenAttachedToWindow(onAttachedToWindow: () -> Unit) {
187         if (isAttachedToWindow) {
188             onAttachedToWindow()
189             return
190         }
191         removeOnAttachStateChangeListener(pendingAttachedToWindowListener)
192         pendingAttachedToWindowListener =
193             object : View.OnAttachStateChangeListener {
194                 override fun onViewAttachedToWindow(v: View) {
195                     onAttachedToWindow()
196                     removeOnAttachStateChangeListener(this)
197                     pendingAttachedToWindowListener = null
198                 }
199 
200                 override fun onViewDetachedFromWindow(v: View) {}
201             }
202         addOnAttachStateChangeListener(pendingAttachedToWindowListener)
203     }
204 
setCornerRoundnessnull205     override fun setCornerRoundness(cornerRoundness: Float) {
206         if (!isSeparateBackgroundEnabled) {
207             return
208         }
209         taskbarBackgroundRenderer.setCornerRoundness(cornerRoundness)
210         separateWindowForTaskbarBackground?.invalidate()
211     }
212 
dumpLogsnull213     override fun dumpLogs(prefix: String, pw: PrintWriter) {
214         pw.println(prefix + "VoiceInteractionWindowController:")
215         pw.println("$prefix\tisSeparateBackgroundEnabled=$isSeparateBackgroundEnabled")
216         pw.println("$prefix\tisVoiceInteractionWindowVisible=$isVoiceInteractionWindowVisible")
217         pw.println(
218             "$prefix\tisSeparateTaskbarBackgroundAttachedToWindow=" +
219                 "${separateWindowForTaskbarBackground?.isAttachedToWindow}"
220         )
221     }
222 }
223