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.controls.shared.model 18 19 import android.app.smartspace.SmartspaceAction 20 import android.content.Context 21 import android.content.Intent 22 import android.content.pm.PackageManager 23 import android.os.Process 24 import android.text.TextUtils 25 import android.util.Log 26 import androidx.annotation.VisibleForTesting 27 import com.android.internal.logging.InstanceId 28 29 @VisibleForTesting const val KEY_SMARTSPACE_APP_NAME = "KEY_SMARTSPACE_APP_NAME" 30 31 /** State of a Smartspace media recommendations view. */ 32 data class SmartspaceMediaData( 33 /** Unique id of a Smartspace media target. */ 34 val targetId: String = "INVALID", 35 /** Indicates if the status is active. */ 36 val isActive: Boolean = false, 37 /** Package name of the media recommendations' provider-app. */ 38 val packageName: String = "INVALID", 39 /** Action to perform when the card is tapped. Also contains the target's extra info. */ 40 val cardAction: SmartspaceAction? = null, 41 /** List of media recommendations. */ 42 val recommendations: List<SmartspaceAction> = emptyList(), 43 /** Intent for the user's initiated dismissal. */ 44 val dismissIntent: Intent? = null, 45 /** The timestamp in milliseconds that the card was generated */ 46 val headphoneConnectionTimeMillis: Long = 0L, 47 /** Instance ID for [MediaUiEventLogger] */ 48 val instanceId: InstanceId? = null, 49 /** The timestamp in milliseconds indicating when the card should be removed */ 50 val expiryTimeMs: Long = 0L, 51 ) { 52 /** 53 * Indicates if all the data is valid. 54 * 55 * TODO(b/230333302): Make MediaControlPanel more flexible so that we can display fewer than 56 * 57 * ``` 58 * [NUM_REQUIRED_RECOMMENDATIONS]. 59 * ``` 60 */ isValidnull61 fun isValid() = getValidRecommendations().size >= NUM_REQUIRED_RECOMMENDATIONS 62 63 /** Returns the list of [recommendations] that have valid data. */ 64 fun getValidRecommendations() = recommendations.filter { it.icon != null } 65 66 /** Returns the upstream app name if available. */ getAppNamenull67 fun getAppName(context: Context): CharSequence? { 68 val nameFromAction = cardAction?.intent?.extras?.getString(KEY_SMARTSPACE_APP_NAME) 69 if (!TextUtils.isEmpty(nameFromAction)) { 70 return nameFromAction 71 } 72 73 val packageManager = context.packageManager 74 packageManager.getLaunchIntentForPackage(packageName)?.let { 75 val launchActivity = it.resolveActivityInfo(packageManager, 0) 76 return launchActivity.loadLabel(packageManager) 77 } 78 79 Log.w( 80 TAG, 81 "Package $packageName does not have a main launcher activity. " + 82 "Fallback to full app name" 83 ) 84 return try { 85 val applicationInfo = packageManager.getApplicationInfo(packageName, /* flags= */ 0) 86 packageManager.getApplicationLabel(applicationInfo) 87 } catch (e: PackageManager.NameNotFoundException) { 88 null 89 } 90 } 91 getUidnull92 fun getUid(context: Context): Int { 93 return try { 94 context.packageManager.getApplicationInfo(packageName, 0 /* flags */).uid 95 } catch (e: PackageManager.NameNotFoundException) { 96 Log.w(TAG, "Fail to get media recommendation's app info", e) 97 Process.INVALID_UID 98 } 99 } 100 } 101 102 /** Key to indicate whether this card should be used to re-show recent media */ 103 const val EXTRA_KEY_TRIGGER_RESUME = "SHOULD_TRIGGER_RESUME" 104 /** Key for extras [SmartspaceMediaData.cardAction] indicating why the card was sent */ 105 const val EXTRA_KEY_TRIGGER_SOURCE = "MEDIA_RECOMMENDATION_TRIGGER_SOURCE" 106 /** Value for [EXTRA_KEY_TRIGGER_SOURCE] when the card is sent on headphone connection */ 107 const val EXTRA_VALUE_TRIGGER_HEADPHONE = "HEADPHONE_CONNECTION" 108 /** Value for key [EXTRA_KEY_TRIGGER_SOURCE] when the card is sent as a regular update */ 109 const val EXTRA_VALUE_TRIGGER_PERIODIC = "PERIODIC_TRIGGER" 110 111 const val NUM_REQUIRED_RECOMMENDATIONS = 3 112 private val TAG = SmartspaceMediaData::class.simpleName!! 113