Merge "Send AGSA the dismiss intent when user dismisses the recommendation card or the reactivated media player (during the recommendation active session)." into sc-qpr1-dev
This commit is contained in:
@@ -75,6 +75,8 @@ public class MediaControlPanel {
|
|||||||
private static final String TAG = "MediaControlPanel";
|
private static final String TAG = "MediaControlPanel";
|
||||||
|
|
||||||
private static final float DISABLED_ALPHA = 0.38f;
|
private static final float DISABLED_ALPHA = 0.38f;
|
||||||
|
private static final String EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME = "com.google"
|
||||||
|
+ ".android.apps.gsa.staticplugins.opa.smartspace.ExportedSmartspaceTrampolineActivity";
|
||||||
private static final String EXTRAS_SMARTSPACE_INTENT =
|
private static final String EXTRAS_SMARTSPACE_INTENT =
|
||||||
"com.google.android.apps.gsa.smartspace.extra.SMARTSPACE_INTENT";
|
"com.google.android.apps.gsa.smartspace.extra.SMARTSPACE_INTENT";
|
||||||
private static final int MEDIA_RECOMMENDATION_ITEMS_PER_ROW = 3;
|
private static final int MEDIA_RECOMMENDATION_ITEMS_PER_ROW = 3;
|
||||||
@@ -627,6 +629,22 @@ public class MediaControlPanel {
|
|||||||
closeGuts();
|
closeGuts();
|
||||||
mMediaDataManagerLazy.get().dismissSmartspaceRecommendation(
|
mMediaDataManagerLazy.get().dismissSmartspaceRecommendation(
|
||||||
data.getTargetId(), MediaViewController.GUTS_ANIMATION_DURATION + 100L);
|
data.getTargetId(), MediaViewController.GUTS_ANIMATION_DURATION + 100L);
|
||||||
|
|
||||||
|
Intent dismissIntent = data.getDismissIntent();
|
||||||
|
if (dismissIntent == null) {
|
||||||
|
Log.w(TAG, "Cannot create dismiss action click action: "
|
||||||
|
+ "extras missing dismiss_intent.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dismissIntent.getComponent() != null
|
||||||
|
&& dismissIntent.getComponent().getClassName()
|
||||||
|
.equals(EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME)) {
|
||||||
|
// Dismiss the card Smartspace data through Smartspace trampoline activity.
|
||||||
|
mContext.startActivity(dismissIntent);
|
||||||
|
} else {
|
||||||
|
mContext.sendBroadcast(dismissIntent);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mController = null;
|
mController = null;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.systemui.media
|
package com.android.systemui.media
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.os.SystemProperties
|
import android.os.SystemProperties
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.android.internal.annotations.VisibleForTesting
|
import com.android.internal.annotations.VisibleForTesting
|
||||||
@@ -32,6 +33,8 @@ import kotlin.collections.LinkedHashMap
|
|||||||
|
|
||||||
private const val TAG = "MediaDataFilter"
|
private const val TAG = "MediaDataFilter"
|
||||||
private const val DEBUG = true
|
private const val DEBUG = true
|
||||||
|
private const val EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME = ("com.google" +
|
||||||
|
".android.apps.gsa.staticplugins.opa.smartspace.ExportedSmartspaceTrampolineActivity")
|
||||||
private const val RESUMABLE_MEDIA_MAX_AGE_SECONDS_KEY = "resumable_media_max_age_seconds"
|
private const val RESUMABLE_MEDIA_MAX_AGE_SECONDS_KEY = "resumable_media_max_age_seconds"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,6 +54,7 @@ internal val SMARTSPACE_MAX_AGE = SystemProperties
|
|||||||
* background users (e.g. timeouts).
|
* background users (e.g. timeouts).
|
||||||
*/
|
*/
|
||||||
class MediaDataFilter @Inject constructor(
|
class MediaDataFilter @Inject constructor(
|
||||||
|
private val context: Context,
|
||||||
private val broadcastDispatcher: BroadcastDispatcher,
|
private val broadcastDispatcher: BroadcastDispatcher,
|
||||||
private val mediaResumeListener: MediaResumeListener,
|
private val mediaResumeListener: MediaResumeListener,
|
||||||
private val lockscreenUserManager: NotificationLockscreenUserManager,
|
private val lockscreenUserManager: NotificationLockscreenUserManager,
|
||||||
@@ -229,6 +233,18 @@ class MediaDataFilter @Inject constructor(
|
|||||||
mediaDataManager.setTimedOut(it, timedOut = true, forceUpdate = true)
|
mediaDataManager.setTimedOut(it, timedOut = true, forceUpdate = true)
|
||||||
}
|
}
|
||||||
if (smartspaceMediaData.isActive) {
|
if (smartspaceMediaData.isActive) {
|
||||||
|
val dismissIntent = smartspaceMediaData.dismissIntent
|
||||||
|
if (dismissIntent == null) {
|
||||||
|
Log.w(TAG, "Cannot create dismiss action click action: " +
|
||||||
|
"extras missing dismiss_intent.")
|
||||||
|
} else if (dismissIntent.getComponent() != null &&
|
||||||
|
dismissIntent.getComponent().getClassName()
|
||||||
|
== EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME) {
|
||||||
|
// Dismiss the card Smartspace data through Smartspace trampoline activity.
|
||||||
|
context.startActivity(dismissIntent)
|
||||||
|
} else {
|
||||||
|
context.sendBroadcast(dismissIntent)
|
||||||
|
}
|
||||||
smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
|
smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
|
||||||
targetId = smartspaceMediaData.targetId, isValid = smartspaceMediaData.isValid)
|
targetId = smartspaceMediaData.targetId, isValid = smartspaceMediaData.isValid)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,12 +76,13 @@ private val ART_URIS = arrayOf(
|
|||||||
|
|
||||||
private const val TAG = "MediaDataManager"
|
private const val TAG = "MediaDataManager"
|
||||||
private const val DEBUG = true
|
private const val DEBUG = true
|
||||||
|
private const val EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY = "dismiss_intent"
|
||||||
|
|
||||||
private val LOADING = MediaData(-1, false, 0, null, null, null, null, null,
|
private val LOADING = MediaData(-1, false, 0, null, null, null, null, null,
|
||||||
emptyList(), emptyList(), "INVALID", null, null, null, true, null)
|
emptyList(), emptyList(), "INVALID", null, null, null, true, null)
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
internal val EMPTY_SMARTSPACE_MEDIA_DATA = SmartspaceMediaData("INVALID", false, false,
|
internal val EMPTY_SMARTSPACE_MEDIA_DATA = SmartspaceMediaData("INVALID", false, false,
|
||||||
"INVALID", null, emptyList(), 0)
|
"INVALID", null, emptyList(), null, 0)
|
||||||
|
|
||||||
fun isMediaNotification(sbn: StatusBarNotification): Boolean {
|
fun isMediaNotification(sbn: StatusBarNotification): Boolean {
|
||||||
if (!sbn.notification.hasMediaSession()) {
|
if (!sbn.notification.hasMediaSession()) {
|
||||||
@@ -883,12 +884,22 @@ class MediaDataManager(
|
|||||||
target: SmartspaceTarget,
|
target: SmartspaceTarget,
|
||||||
isActive: Boolean
|
isActive: Boolean
|
||||||
): SmartspaceMediaData {
|
): SmartspaceMediaData {
|
||||||
|
var dismissIntent: Intent? = null
|
||||||
|
if (target.baseAction != null && target.baseAction.extras != null) {
|
||||||
|
dismissIntent = target
|
||||||
|
.baseAction
|
||||||
|
.extras
|
||||||
|
.getParcelable(EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY) as Intent
|
||||||
|
}
|
||||||
packageName(target)?.let {
|
packageName(target)?.let {
|
||||||
return SmartspaceMediaData(target.smartspaceTargetId, isActive, true, it,
|
return SmartspaceMediaData(target.smartspaceTargetId, isActive, true, it,
|
||||||
target.baseAction, target.iconGrid, 0)
|
target.baseAction, target.iconGrid,
|
||||||
|
dismissIntent, 0)
|
||||||
}
|
}
|
||||||
return EMPTY_SMARTSPACE_MEDIA_DATA
|
return EMPTY_SMARTSPACE_MEDIA_DATA
|
||||||
.copy(targetId = target.smartspaceTargetId, isActive = isActive)
|
.copy(targetId = target.smartspaceTargetId,
|
||||||
|
isActive = isActive,
|
||||||
|
dismissIntent = dismissIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun packageName(target: SmartspaceTarget): String? {
|
private fun packageName(target: SmartspaceTarget): String? {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.systemui.media
|
package com.android.systemui.media
|
||||||
|
|
||||||
import android.app.smartspace.SmartspaceAction
|
import android.app.smartspace.SmartspaceAction
|
||||||
|
import android.content.Intent
|
||||||
|
|
||||||
/** State of a Smartspace media recommendations view. */
|
/** State of a Smartspace media recommendations view. */
|
||||||
data class SmartspaceMediaData(
|
data class SmartspaceMediaData(
|
||||||
@@ -44,6 +45,10 @@ data class SmartspaceMediaData(
|
|||||||
* List of media recommendations.
|
* List of media recommendations.
|
||||||
*/
|
*/
|
||||||
val recommendations: List<SmartspaceAction>,
|
val recommendations: List<SmartspaceAction>,
|
||||||
|
/**
|
||||||
|
* Intent for the user's initiated dismissal.
|
||||||
|
*/
|
||||||
|
val dismissIntent: Intent?,
|
||||||
/**
|
/**
|
||||||
* View's background color.
|
* View's background color.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class MediaDataFilterTest : SysuiTestCase() {
|
|||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
mediaDataFilter = MediaDataFilter(broadcastDispatcher, mediaResumeListener,
|
mediaDataFilter = MediaDataFilter(context, broadcastDispatcher, mediaResumeListener,
|
||||||
lockscreenUserManager, executor, clock)
|
lockscreenUserManager, executor, clock)
|
||||||
mediaDataFilter.mediaDataManager = mediaDataManager
|
mediaDataFilter.mediaDataManager = mediaDataManager
|
||||||
mediaDataFilter.addListener(listener)
|
mediaDataFilter.addListener(listener)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.Notification.MediaStyle
|
|||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.app.smartspace.SmartspaceAction
|
import android.app.smartspace.SmartspaceAction
|
||||||
import android.app.smartspace.SmartspaceTarget
|
import android.app.smartspace.SmartspaceTarget
|
||||||
|
import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.media.MediaDescription
|
import android.media.MediaDescription
|
||||||
import android.media.MediaMetadata
|
import android.media.MediaMetadata
|
||||||
@@ -51,6 +52,7 @@ private const val APP_NAME = "SystemUI"
|
|||||||
private const val SESSION_ARTIST = "artist"
|
private const val SESSION_ARTIST = "artist"
|
||||||
private const val SESSION_TITLE = "title"
|
private const val SESSION_TITLE = "title"
|
||||||
private const val USER_ID = 0
|
private const val USER_ID = 0
|
||||||
|
private val DISMISS_INTENT = Intent().apply { action = "dismiss" }
|
||||||
|
|
||||||
private fun <T> anyObject(): T {
|
private fun <T> anyObject(): T {
|
||||||
return Mockito.anyObject<T>()
|
return Mockito.anyObject<T>()
|
||||||
@@ -83,6 +85,7 @@ class MediaDataManagerTest : SysuiTestCase() {
|
|||||||
lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider
|
lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider
|
||||||
@Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget
|
@Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget
|
||||||
@Mock private lateinit var mediaRecommendationItem: SmartspaceAction
|
@Mock private lateinit var mediaRecommendationItem: SmartspaceAction
|
||||||
|
@Mock private lateinit var mediaSmartspaceBaseAction: SmartspaceAction
|
||||||
lateinit var mediaDataManager: MediaDataManager
|
lateinit var mediaDataManager: MediaDataManager
|
||||||
lateinit var mediaNotification: StatusBarNotification
|
lateinit var mediaNotification: StatusBarNotification
|
||||||
@Captor lateinit var mediaDataCaptor: ArgumentCaptor<MediaData>
|
@Captor lateinit var mediaDataCaptor: ArgumentCaptor<MediaData>
|
||||||
@@ -146,8 +149,12 @@ class MediaDataManagerTest : SysuiTestCase() {
|
|||||||
// treat mediaSessionBasedFilter as a listener for testing.
|
// treat mediaSessionBasedFilter as a listener for testing.
|
||||||
listener = mediaSessionBasedFilter
|
listener = mediaSessionBasedFilter
|
||||||
|
|
||||||
val recommendationExtras = Bundle()
|
val recommendationExtras = Bundle().apply {
|
||||||
recommendationExtras.putString("package_name", PACKAGE_NAME)
|
putString("package_name", PACKAGE_NAME)
|
||||||
|
putParcelable("dismiss_intent", DISMISS_INTENT)
|
||||||
|
}
|
||||||
|
whenever(mediaSmartspaceBaseAction.extras).thenReturn(recommendationExtras)
|
||||||
|
whenever(mediaSmartspaceTarget.baseAction).thenReturn(mediaSmartspaceBaseAction)
|
||||||
whenever(mediaRecommendationItem.extras).thenReturn(recommendationExtras)
|
whenever(mediaRecommendationItem.extras).thenReturn(recommendationExtras)
|
||||||
whenever(mediaSmartspaceTarget.smartspaceTargetId).thenReturn(KEY_MEDIA_SMARTSPACE)
|
whenever(mediaSmartspaceTarget.smartspaceTargetId).thenReturn(KEY_MEDIA_SMARTSPACE)
|
||||||
whenever(mediaSmartspaceTarget.featureType).thenReturn(SmartspaceTarget.FEATURE_MEDIA)
|
whenever(mediaSmartspaceTarget.featureType).thenReturn(SmartspaceTarget.FEATURE_MEDIA)
|
||||||
@@ -380,7 +387,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
|||||||
verify(listener).onSmartspaceMediaDataLoaded(
|
verify(listener).onSmartspaceMediaDataLoaded(
|
||||||
eq(KEY_MEDIA_SMARTSPACE),
|
eq(KEY_MEDIA_SMARTSPACE),
|
||||||
eq(SmartspaceMediaData(KEY_MEDIA_SMARTSPACE, true /* isActive */, true /*isValid */,
|
eq(SmartspaceMediaData(KEY_MEDIA_SMARTSPACE, true /* isActive */, true /*isValid */,
|
||||||
PACKAGE_NAME, null, listOf(mediaRecommendationItem), 0)),
|
PACKAGE_NAME, mediaSmartspaceBaseAction, listOf(mediaRecommendationItem),
|
||||||
|
DISMISS_INTENT, 0)),
|
||||||
eq(false))
|
eq(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,7 +399,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
|||||||
verify(listener).onSmartspaceMediaDataLoaded(
|
verify(listener).onSmartspaceMediaDataLoaded(
|
||||||
eq(KEY_MEDIA_SMARTSPACE),
|
eq(KEY_MEDIA_SMARTSPACE),
|
||||||
eq(EMPTY_SMARTSPACE_MEDIA_DATA
|
eq(EMPTY_SMARTSPACE_MEDIA_DATA
|
||||||
.copy(targetId = KEY_MEDIA_SMARTSPACE, isActive = true, isValid = false)),
|
.copy(targetId = KEY_MEDIA_SMARTSPACE, isActive = true,
|
||||||
|
isValid = false, dismissIntent = DISMISS_INTENT)),
|
||||||
eq(false))
|
eq(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user