1 /*
2  * Copyright (C) 2020 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.systemui.media.dialog
18 
19 import android.content.Context
20 import android.media.session.MediaSession
21 import android.os.UserHandle
22 import android.view.View
23 import com.android.internal.jank.InteractionJankMonitor
24 import com.android.internal.logging.UiEventLogger
25 import com.android.systemui.animation.DialogCuj
26 import com.android.systemui.animation.DialogTransitionAnimator
27 import com.android.systemui.broadcast.BroadcastSender
28 import javax.inject.Inject
29 
30 /** Manager to create and show a [MediaOutputDialog]. */
31 open class MediaOutputDialogManager
32 @Inject
33 constructor(
34     private val context: Context,
35     private val broadcastSender: BroadcastSender,
36     private val uiEventLogger: UiEventLogger,
37     private val dialogTransitionAnimator: DialogTransitionAnimator,
38     private val mediaOutputControllerFactory: MediaOutputController.Factory,
39 ) {
40     companion object {
41         const val INTERACTION_JANK_TAG = "media_output"
42         var mediaOutputDialog: MediaOutputDialog? = null
43     }
44 
45     /** Creates a [MediaOutputDialog] for the given package. */
46     // TODO: b/321969740 - Make the userHandle non-optional, and place the parameter next to the
47     // package name. The user handle is necessary to disambiguate the same package running on
48     // different users.
createAndShownull49     open fun createAndShow(
50         packageName: String,
51         aboveStatusBar: Boolean,
52         view: View? = null,
53         userHandle: UserHandle? = null,
54         token: MediaSession.Token? = null
55     ) {
56         createAndShowWithController(
57             packageName,
58             aboveStatusBar,
59             controller =
60                 view?.let {
61                     DialogTransitionAnimator.Controller.fromView(
62                         it,
63                         DialogCuj(
64                             InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
65                             INTERACTION_JANK_TAG
66                         )
67                     )
68                 },
69             userHandle = userHandle,
70             token = token,
71         )
72     }
73 
74     /** Creates a [MediaOutputDialog] for the given package. */
75     // TODO: b/321969740 - Make the userHandle non-optional, and place the parameter next to the
76     // package name. The user handle is necessary to disambiguate the same package running on
77     // different users.
createAndShowWithControllernull78     open fun createAndShowWithController(
79         packageName: String,
80         aboveStatusBar: Boolean,
81         controller: DialogTransitionAnimator.Controller?,
82         userHandle: UserHandle? = null,
83         token: MediaSession.Token? = null,
84     ) {
85         createAndShow(
86             packageName,
87             aboveStatusBar,
88             dialogTransitionAnimatorController = controller,
89             includePlaybackAndAppMetadata = true,
90             userHandle = userHandle,
91             token = token,
92         )
93     }
94 
createAndShowForSystemRoutingnull95     open fun createAndShowForSystemRouting(
96         controller: DialogTransitionAnimator.Controller? = null
97     ) {
98         createAndShow(
99             packageName = null,
100             aboveStatusBar = false,
101             dialogTransitionAnimatorController = null,
102             includePlaybackAndAppMetadata = false,
103             userHandle = null,
104         )
105     }
106 
107     // TODO: b/321969740 - Make the userHandle non-optional, and place the parameter next to the
108     // package name. The user handle is necessary to disambiguate the same package running on
109     // different users.
createAndShownull110     private fun createAndShow(
111         packageName: String?,
112         aboveStatusBar: Boolean,
113         dialogTransitionAnimatorController: DialogTransitionAnimator.Controller?,
114         includePlaybackAndAppMetadata: Boolean = true,
115         userHandle: UserHandle? = null,
116         token: MediaSession.Token? = null,
117     ) {
118         // Dismiss the previous dialog, if any.
119         mediaOutputDialog?.dismiss()
120 
121         val controller = mediaOutputControllerFactory.create(packageName, userHandle, token)
122 
123         val mediaOutputDialog =
124             MediaOutputDialog(
125                 context,
126                 aboveStatusBar,
127                 broadcastSender,
128                 controller,
129                 dialogTransitionAnimator,
130                 uiEventLogger,
131                 includePlaybackAndAppMetadata
132             )
133 
134         // Show the dialog.
135         if (dialogTransitionAnimatorController != null) {
136             dialogTransitionAnimator.show(
137                 mediaOutputDialog,
138                 dialogTransitionAnimatorController,
139             )
140         } else {
141             mediaOutputDialog.show()
142         }
143     }
144 
145     /** dismiss [MediaOutputDialog] if exist. */
dismissnull146     open fun dismiss() {
147         mediaOutputDialog?.dismiss()
148         mediaOutputDialog = null
149     }
150 }
151