Merge changes from topic "media_delete_intent_rvc_qpr2" into rvc-qpr-dev
* changes: Notifications starting paused shall still be subject to timeout. Disable player's "Dismiss" button when notification is not dismissible. Media player attempts to dismiss notifications when players removed.
This commit is contained in:
@@ -2820,6 +2820,8 @@
|
|||||||
<string name="controls_media_title">Media</string>
|
<string name="controls_media_title">Media</string>
|
||||||
<!-- Explanation for closing controls associated with a specific media session [CHAR_LIMIT=NONE] -->
|
<!-- Explanation for closing controls associated with a specific media session [CHAR_LIMIT=NONE] -->
|
||||||
<string name="controls_media_close_session">Hide the current session.</string>
|
<string name="controls_media_close_session">Hide the current session.</string>
|
||||||
|
<!-- Explanation that controls associated with a specific media session are active [CHAR_LIMIT=NONE] -->
|
||||||
|
<string name="controls_media_active_session">Current session cannot be hidden.</string>
|
||||||
<!-- Label for a button that will hide media controls [CHAR_LIMIT=30] -->
|
<!-- Label for a button that will hide media controls [CHAR_LIMIT=30] -->
|
||||||
<string name="controls_media_dismiss_button">Dismiss</string>
|
<string name="controls_media_dismiss_button">Dismiss</string>
|
||||||
<!-- Label for button to resume media playback [CHAR_LIMIT=NONE] -->
|
<!-- Label for button to resume media playback [CHAR_LIMIT=NONE] -->
|
||||||
|
|||||||
@@ -359,7 +359,15 @@ public class MediaControlPanel {
|
|||||||
final MediaController controller = getController();
|
final MediaController controller = getController();
|
||||||
mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
|
mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
|
||||||
|
|
||||||
|
// Guts label
|
||||||
|
boolean isDismissible = data.isClearable();
|
||||||
|
mViewHolder.getSettingsText().setText(isDismissible
|
||||||
|
? R.string.controls_media_close_session
|
||||||
|
: R.string.controls_media_active_session);
|
||||||
|
|
||||||
// Dismiss
|
// Dismiss
|
||||||
|
mViewHolder.getDismissLabel().setAlpha(isDismissible ? 1 : DISABLED_ALPHA);
|
||||||
|
mViewHolder.getDismiss().setEnabled(isDismissible);
|
||||||
mViewHolder.getDismiss().setOnClickListener(v -> {
|
mViewHolder.getDismiss().setOnClickListener(v -> {
|
||||||
if (mKey != null) {
|
if (mKey != null) {
|
||||||
closeGuts();
|
closeGuts();
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class MediaTimeoutListener @Inject constructor(
|
|||||||
/**
|
/**
|
||||||
* Callback representing that a media object is now expired:
|
* Callback representing that a media object is now expired:
|
||||||
* @param token Media session unique identifier
|
* @param token Media session unique identifier
|
||||||
* @param pauseTimeuot True when expired for {@code PAUSED_MEDIA_TIMEOUT}
|
* @param pauseTimeout True when expired for {@code PAUSED_MEDIA_TIMEOUT}
|
||||||
*/
|
*/
|
||||||
lateinit var timeoutCallback: (String, Boolean) -> Unit
|
lateinit var timeoutCallback: (String, Boolean) -> Unit
|
||||||
|
|
||||||
@@ -57,11 +57,10 @@ class MediaTimeoutListener @Inject constructor(
|
|||||||
// Having an old key means that we're migrating from/to resumption. We should update
|
// Having an old key means that we're migrating from/to resumption. We should update
|
||||||
// the old listener to make sure that events will be dispatched to the new location.
|
// the old listener to make sure that events will be dispatched to the new location.
|
||||||
val migrating = oldKey != null && key != oldKey
|
val migrating = oldKey != null && key != oldKey
|
||||||
var wasPlaying = false
|
|
||||||
if (migrating) {
|
if (migrating) {
|
||||||
val reusedListener = mediaListeners.remove(oldKey)
|
val reusedListener = mediaListeners.remove(oldKey)
|
||||||
if (reusedListener != null) {
|
if (reusedListener != null) {
|
||||||
wasPlaying = reusedListener.playing ?: false
|
val wasPlaying = reusedListener.playing ?: false
|
||||||
if (DEBUG) Log.d(TAG, "migrating key $oldKey to $key, for resumption")
|
if (DEBUG) Log.d(TAG, "migrating key $oldKey to $key, for resumption")
|
||||||
reusedListener.mediaData = data
|
reusedListener.mediaData = data
|
||||||
reusedListener.key = key
|
reusedListener.key = key
|
||||||
@@ -159,9 +158,8 @@ class MediaTimeoutListener @Inject constructor(
|
|||||||
Log.v(TAG, "Execute timeout for $key")
|
Log.v(TAG, "Execute timeout for $key")
|
||||||
}
|
}
|
||||||
timedOut = true
|
timedOut = true
|
||||||
if (dispatchEvents) {
|
// this event is async, so it's safe even when `dispatchEvents` is false
|
||||||
timeoutCallback(key, timedOut)
|
timeoutCallback(key, timedOut)
|
||||||
}
|
|
||||||
}, PAUSED_MEDIA_TIMEOUT)
|
}, PAUSED_MEDIA_TIMEOUT)
|
||||||
} else {
|
} else {
|
||||||
expireMediaTimeout(key, "playback started - $state, $key")
|
expireMediaTimeout(key, "playback started - $state, $key")
|
||||||
|
|||||||
@@ -60,8 +60,10 @@ class PlayerViewHolder private constructor(itemView: View) {
|
|||||||
val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
|
val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
|
||||||
|
|
||||||
// Settings screen
|
// Settings screen
|
||||||
|
val settingsText = itemView.requireViewById<TextView>(R.id.remove_text)
|
||||||
val cancel = itemView.requireViewById<View>(R.id.cancel)
|
val cancel = itemView.requireViewById<View>(R.id.cancel)
|
||||||
val dismiss = itemView.requireViewById<View>(R.id.dismiss)
|
val dismiss = itemView.requireViewById<ViewGroup>(R.id.dismiss)
|
||||||
|
val dismissLabel = dismiss.getChildAt(0)
|
||||||
val settings = itemView.requireViewById<View>(R.id.settings)
|
val settings = itemView.requireViewById<View>(R.id.settings)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import android.os.Trace;
|
|||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
import android.provider.DeviceConfig.Properties;
|
import android.provider.DeviceConfig.Properties;
|
||||||
|
import android.service.notification.NotificationListenerService;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -52,6 +53,7 @@ import com.android.systemui.Dumpable;
|
|||||||
import com.android.systemui.Interpolators;
|
import com.android.systemui.Interpolators;
|
||||||
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
|
import com.android.systemui.media.MediaData;
|
||||||
import com.android.systemui.media.MediaDataManager;
|
import com.android.systemui.media.MediaDataManager;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
import com.android.systemui.statusbar.dagger.StatusBarModule;
|
import com.android.systemui.statusbar.dagger.StatusBarModule;
|
||||||
@@ -250,6 +252,24 @@ public class NotificationMediaManager implements Dumpable {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mMediaDataManager.addListener(new MediaDataManager.Listener() {
|
||||||
|
@Override
|
||||||
|
public void onMediaDataLoaded(@NonNull String key,
|
||||||
|
@Nullable String oldKey, @NonNull MediaData data) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMediaDataRemoved(@NonNull String key) {
|
||||||
|
NotificationEntry entry = mEntryManager.getPendingOrActiveNotif(key);
|
||||||
|
if (entry != null) {
|
||||||
|
// TODO(b/160713608): "removing" this notification won't happen and
|
||||||
|
// won't send the 'deleteIntent' if the notification is ongoing.
|
||||||
|
mEntryManager.performRemoveNotification(entry.getSbn(),
|
||||||
|
NotificationListenerService.REASON_CANCEL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
mShowCompactMediaSeekbar = "true".equals(
|
mShowCompactMediaSeekbar = "true".equals(
|
||||||
DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
|
DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
|
||||||
SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED));
|
SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED));
|
||||||
|
|||||||
@@ -109,9 +109,11 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
|||||||
private lateinit var action2: ImageButton
|
private lateinit var action2: ImageButton
|
||||||
private lateinit var action3: ImageButton
|
private lateinit var action3: ImageButton
|
||||||
private lateinit var action4: ImageButton
|
private lateinit var action4: ImageButton
|
||||||
|
private lateinit var settingsText: TextView
|
||||||
private lateinit var settings: View
|
private lateinit var settings: View
|
||||||
private lateinit var cancel: View
|
private lateinit var cancel: View
|
||||||
private lateinit var dismiss: View
|
private lateinit var dismiss: FrameLayout
|
||||||
|
private lateinit var dismissLabel: View
|
||||||
|
|
||||||
private lateinit var session: MediaSession
|
private lateinit var session: MediaSession
|
||||||
private val device = MediaDeviceData(true, null, DEVICE_NAME)
|
private val device = MediaDeviceData(true, null, DEVICE_NAME)
|
||||||
@@ -168,12 +170,16 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
|||||||
whenever(holder.action3).thenReturn(action3)
|
whenever(holder.action3).thenReturn(action3)
|
||||||
action4 = ImageButton(context)
|
action4 = ImageButton(context)
|
||||||
whenever(holder.action4).thenReturn(action4)
|
whenever(holder.action4).thenReturn(action4)
|
||||||
|
settingsText = TextView(context)
|
||||||
|
whenever(holder.settingsText).thenReturn(settingsText)
|
||||||
settings = View(context)
|
settings = View(context)
|
||||||
whenever(holder.settings).thenReturn(settings)
|
whenever(holder.settings).thenReturn(settings)
|
||||||
cancel = View(context)
|
cancel = View(context)
|
||||||
whenever(holder.cancel).thenReturn(cancel)
|
whenever(holder.cancel).thenReturn(cancel)
|
||||||
dismiss = View(context)
|
dismiss = FrameLayout(context)
|
||||||
whenever(holder.dismiss).thenReturn(dismiss)
|
whenever(holder.dismiss).thenReturn(dismiss)
|
||||||
|
dismissLabel = View(context)
|
||||||
|
whenever(holder.dismissLabel).thenReturn(dismissLabel)
|
||||||
|
|
||||||
// Create media session
|
// Create media session
|
||||||
val metadataBuilder = MediaMetadata.Builder().apply {
|
val metadataBuilder = MediaMetadata.Builder().apply {
|
||||||
@@ -327,6 +333,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
|||||||
notificationKey = KEY)
|
notificationKey = KEY)
|
||||||
player.bind(state, mediaKey)
|
player.bind(state, mediaKey)
|
||||||
|
|
||||||
|
assertThat(dismiss.isEnabled).isEqualTo(true)
|
||||||
dismiss.callOnClick()
|
dismiss.callOnClick()
|
||||||
val captor = ArgumentCaptor.forClass(ActivityStarter.OnDismissAction::class.java)
|
val captor = ArgumentCaptor.forClass(ActivityStarter.OnDismissAction::class.java)
|
||||||
verify(keyguardDismissUtil).executeWhenUnlocked(captor.capture(), anyBoolean())
|
verify(keyguardDismissUtil).executeWhenUnlocked(captor.capture(), anyBoolean())
|
||||||
@@ -334,4 +341,16 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
|||||||
captor.value.onDismiss()
|
captor.value.onDismiss()
|
||||||
verify(mediaDataManager).dismissMediaData(eq(mediaKey), anyLong())
|
verify(mediaDataManager).dismissMediaData(eq(mediaKey), anyLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dismissButtonDisabled() {
|
||||||
|
val mediaKey = "key for dismissal"
|
||||||
|
player.attach(holder)
|
||||||
|
val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
|
||||||
|
emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null,
|
||||||
|
isClearable = false, notificationKey = KEY)
|
||||||
|
player.bind(state, mediaKey)
|
||||||
|
|
||||||
|
assertThat(dismiss.isEnabled).isEqualTo(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user