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 com.android.systemui.dagger.qualifiers.Background 29 import com.android.systemui.dagger.qualifiers.Main 30 import java.util.concurrent.Executor 31 import javax.inject.Inject 32 33 /** Manager to create and show a [MediaOutputDialog]. */ 34 open class MediaOutputDialogManager 35 @Inject 36 constructor( 37 private val context: Context, 38 private val broadcastSender: BroadcastSender, 39 private val uiEventLogger: UiEventLogger, 40 private val dialogTransitionAnimator: DialogTransitionAnimator, 41 private val mediaSwitchingControllerFactory: MediaSwitchingController.Factory, 42 ) { 43 @Inject @Main lateinit var mainExecutor: Executor 44 @Inject @Background lateinit var backgroundExecutor: Executor 45 46 companion object { 47 const val INTERACTION_JANK_TAG = "media_output" 48 var mediaOutputDialog: MediaOutputDialog? = null 49 } 50 51 /** Creates a [MediaOutputDialog] for the given package. */ 52 // TODO: b/321969740 - Make the userHandle non-optional, and place the parameter next to the 53 // package name. The user handle is necessary to disambiguate the same package running on 54 // different users. createAndShownull55 open fun createAndShow( 56 packageName: String, 57 aboveStatusBar: Boolean, 58 view: View? = null, 59 userHandle: UserHandle? = null, 60 token: MediaSession.Token? = null, 61 ) { 62 createAndShowWithController( 63 packageName, 64 aboveStatusBar, 65 controller = 66 view?.let { 67 DialogTransitionAnimator.Controller.fromView( 68 it, 69 DialogCuj( 70 InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, 71 INTERACTION_JANK_TAG, 72 ), 73 ) 74 }, 75 userHandle = userHandle, 76 token = token, 77 ) 78 } 79 80 /** Creates a [MediaOutputDialog] for the given package. */ 81 // TODO: b/321969740 - Make the userHandle non-optional, and place the parameter next to the 82 // package name. The user handle is necessary to disambiguate the same package running on 83 // different users. createAndShowWithControllernull84 open fun createAndShowWithController( 85 packageName: String, 86 aboveStatusBar: Boolean, 87 controller: DialogTransitionAnimator.Controller?, 88 userHandle: UserHandle? = null, 89 token: MediaSession.Token? = null, 90 ) { 91 createAndShow( 92 packageName, 93 aboveStatusBar, 94 dialogTransitionAnimatorController = controller, 95 includePlaybackAndAppMetadata = true, 96 userHandle = userHandle, 97 token = token, 98 ) 99 } 100 createAndShowForSystemRoutingnull101 open fun createAndShowForSystemRouting( 102 controller: DialogTransitionAnimator.Controller? = null 103 ) { 104 createAndShow( 105 packageName = null, 106 aboveStatusBar = false, 107 dialogTransitionAnimatorController = controller, 108 includePlaybackAndAppMetadata = false, 109 userHandle = null, 110 ) 111 } 112 113 // TODO: b/321969740 - Make the userHandle non-optional, and place the parameter next to the 114 // package name. The user handle is necessary to disambiguate the same package running on 115 // different users. createAndShownull116 private fun createAndShow( 117 packageName: String?, 118 aboveStatusBar: Boolean, 119 dialogTransitionAnimatorController: DialogTransitionAnimator.Controller?, 120 includePlaybackAndAppMetadata: Boolean = true, 121 userHandle: UserHandle? = null, 122 token: MediaSession.Token? = null, 123 ) { 124 // Dismiss the previous dialog, if any. 125 mediaOutputDialog?.dismiss() 126 127 val controller = mediaSwitchingControllerFactory.create(packageName, userHandle, token) 128 129 val mediaOutputDialog = 130 MediaOutputDialog( 131 context, 132 aboveStatusBar, 133 broadcastSender, 134 controller, 135 dialogTransitionAnimator, 136 uiEventLogger, 137 mainExecutor, 138 backgroundExecutor, 139 includePlaybackAndAppMetadata, 140 ) 141 142 // Show the dialog. 143 if (dialogTransitionAnimatorController != null) { 144 dialogTransitionAnimator.show(mediaOutputDialog, dialogTransitionAnimatorController) 145 } else { 146 mediaOutputDialog.show() 147 } 148 } 149 150 /** dismiss [MediaOutputDialog] if exist. */ dismissnull151 open fun dismiss() { 152 mediaOutputDialog?.dismiss() 153 mediaOutputDialog = null 154 } 155 } 156