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