1 /* 2 * Copyright (C) 2022 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.taptotransfer.common 18 19 import android.content.Context 20 import android.content.pm.PackageManager 21 import android.graphics.drawable.Drawable 22 import androidx.annotation.AttrRes 23 import androidx.annotation.DrawableRes 24 import com.android.systemui.res.R 25 import com.android.systemui.common.shared.model.ContentDescription 26 import com.android.systemui.common.shared.model.Icon 27 import com.android.systemui.common.shared.model.TintedIcon 28 import com.android.systemui.temporarydisplay.chipbar.ChipbarInfo.Companion.DEFAULT_ICON_TINT 29 30 /** Utility methods for media tap-to-transfer. */ 31 class MediaTttUtils { 32 companion object { 33 const val WINDOW_TITLE_SENDER = "Media Transfer Chip View (Sender)" 34 const val WINDOW_TITLE_RECEIVER = "Media Transfer Chip View (Receiver)" 35 36 const val WAKE_REASON_SENDER = "MEDIA_TRANSFER_ACTIVATED_SENDER" 37 const val WAKE_REASON_RECEIVER = "MEDIA_TRANSFER_ACTIVATED_RECEIVER" 38 39 /** 40 * Returns the information needed to display the icon. 41 * 42 * The information will either contain app name and icon of the app playing media, or a 43 * default name and icon if we can't find the app name/icon. 44 * 45 * @param appPackageName the package name of the app playing the media. 46 * @param onPackageNotFoundException a function run if a 47 * [PackageManager.NameNotFoundException] occurs. 48 * @param isReceiver indicates whether the icon is displayed in a receiver view. 49 */ getIconInfoFromPackageNamenull50 fun getIconInfoFromPackageName( 51 context: Context, 52 appPackageName: String?, 53 isReceiver: Boolean, 54 onPackageNotFoundException: () -> Unit, 55 ): IconInfo { 56 if (appPackageName != null) { 57 val packageManager = context.packageManager 58 try { 59 val appName = 60 packageManager 61 .getApplicationInfo( 62 appPackageName, 63 PackageManager.ApplicationInfoFlags.of(0), 64 ) 65 .loadLabel(packageManager) 66 .toString() 67 val contentDescription = 68 if (isReceiver) { 69 ContentDescription.Loaded( 70 context.getString( 71 R.string 72 .media_transfer_receiver_content_description_with_app_name, 73 appName 74 ) 75 ) 76 } else { 77 ContentDescription.Loaded(appName) 78 } 79 return IconInfo( 80 contentDescription, 81 MediaTttIcon.Loaded(packageManager.getApplicationIcon(appPackageName)), 82 tint = null, 83 isAppIcon = true 84 ) 85 } catch (e: PackageManager.NameNotFoundException) { 86 onPackageNotFoundException.invoke() 87 } 88 } 89 return IconInfo( 90 if (isReceiver) { 91 ContentDescription.Resource( 92 R.string.media_transfer_receiver_content_description_unknown_app 93 ) 94 } else { 95 ContentDescription.Resource( 96 R.string.media_output_dialog_unknown_launch_app_name 97 ) 98 }, 99 MediaTttIcon.Resource(R.drawable.ic_cast), 100 tint = DEFAULT_ICON_TINT, 101 isAppIcon = false 102 ) 103 } 104 } 105 } 106 107 /** Stores all the information for an icon shown with media TTT. */ 108 data class IconInfo( 109 val contentDescription: ContentDescription, 110 val icon: MediaTttIcon, 111 @AttrRes val tint: Int?, 112 /** 113 * True if [drawable] is the app's icon, and false if [drawable] is some generic default icon. 114 */ 115 val isAppIcon: Boolean 116 ) { 117 /** Converts this into a [TintedIcon]. */ toTintedIconnull118 fun toTintedIcon(): TintedIcon { 119 val iconOutput = 120 when (icon) { 121 is MediaTttIcon.Loaded -> Icon.Loaded(icon.drawable, contentDescription) 122 is MediaTttIcon.Resource -> Icon.Resource(icon.res, contentDescription) 123 } 124 return TintedIcon(iconOutput, tint) 125 } 126 } 127 128 /** 129 * Mimics [com.android.systemui.common.shared.model.Icon] but without the content description, since 130 * the content description may need to be overridden. 131 */ 132 sealed interface MediaTttIcon { 133 data class Loaded(val drawable: Drawable) : MediaTttIcon 134 data class Resource(@DrawableRes val res: Int) : MediaTttIcon 135 } 136