diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt index 87905f2c05bca..b163818f68a82 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt @@ -24,7 +24,6 @@ import android.app.NotificationChannelGroup import android.app.NotificationManager.IMPORTANCE_NONE import android.app.NotificationManager.Importance import android.content.Context -import android.content.DialogInterface import android.graphics.Color import android.graphics.PixelFormat import android.graphics.drawable.ColorDrawable @@ -79,9 +78,10 @@ class ChannelEditorDialogController @Inject constructor( // Caller should set this if they care about when we dismiss var onFinishListener: OnChannelEditorDialogFinishedListener? = null - // Channels handed to us from NotificationInfo @VisibleForTesting - internal val providedChannels = mutableListOf() + internal val paddedChannels = mutableListOf() + // Channels handed to us from NotificationInfo + private val providedChannels = mutableListOf() // Map from NotificationChannel to importance private val edits = mutableMapOf() @@ -119,6 +119,8 @@ class ChannelEditorDialogController @Inject constructor( channelGroupList.clear() channelGroupList.addAll(fetchNotificationChannelGroups()) buildGroupNameLookup() + providedChannels.clear() + providedChannels.addAll(channels) padToFourChannels(channels) initDialog() @@ -134,21 +136,21 @@ class ChannelEditorDialogController @Inject constructor( } private fun padToFourChannels(channels: Set) { - providedChannels.clear() + paddedChannels.clear() // First, add all of the given channels - providedChannels.addAll(channels.asSequence().take(4)) + paddedChannels.addAll(channels.asSequence().take(4)) // Then pad to 4 if we haven't been given that many - providedChannels.addAll(getDisplayableChannels(channelGroupList.asSequence()) - .filterNot { providedChannels.contains(it) } + paddedChannels.addAll(getDisplayableChannels(channelGroupList.asSequence()) + .filterNot { paddedChannels.contains(it) } .distinct() - .take(4 - providedChannels.size)) + .take(4 - paddedChannels.size)) // If we only got one channel and it has the default miscellaneous tag, then we actually // are looking at an app with a targetSdk <= O, and it doesn't make much sense to show the // channel - if (providedChannels.size == 1 && DEFAULT_CHANNEL_ID == providedChannels[0].id) { - providedChannels.clear() + if (paddedChannels.size == 1 && DEFAULT_CHANNEL_ID == paddedChannels[0].id) { + paddedChannels.clear() } } @@ -196,6 +198,7 @@ class ChannelEditorDialogController @Inject constructor( appNotificationsCurrentlyEnabled = null edits.clear() + paddedChannels.clear() providedChannels.clear() groupNameLookup.clear() } @@ -292,16 +295,21 @@ class ChannelEditorDialogController @Inject constructor( dialog.apply { setContentView(R.layout.notif_half_shelf) setCanceledOnTouchOutside(true) - setOnDismissListener(object : DialogInterface.OnDismissListener { - override fun onDismiss(dialog: DialogInterface?) { - onFinishListener?.onChannelEditorDialogFinished() - } - }) - findViewById(R.id.half_shelf_container)?.apply { + setOnDismissListener { onFinishListener?.onChannelEditorDialogFinished() } + + val listView = findViewById(R.id.half_shelf_container) + listView?.apply { controller = this@ChannelEditorDialogController appIcon = this@ChannelEditorDialogController.appIcon appName = this@ChannelEditorDialogController.appName - channels = providedChannels + channels = paddedChannels + } + + setOnShowListener { + // play a highlight animation for the given channels + for (channel in providedChannels) { + listView?.highlightChannel(channel) + } } findViewById(R.id.done_button)?.setOnClickListener { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt index b776123129c70..38a1579222b1e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.row +import android.animation.ArgbEvaluator +import android.animation.ValueAnimator import android.app.NotificationChannel import android.app.NotificationManager.IMPORTANCE_DEFAULT import android.app.NotificationManager.IMPORTANCE_NONE @@ -33,8 +35,10 @@ import android.widget.ImageView import android.widget.LinearLayout import android.widget.Switch import android.widget.TextView +import com.android.settingslib.Utils import com.android.systemui.R +import com.android.systemui.util.Assert /** * Half-shelf for notification channel controls @@ -51,6 +55,7 @@ class ChannelEditorListView(c: Context, attrs: AttributeSet) : LinearLayout(c, a // The first row is for the entire app private lateinit var appControlRow: AppControlView + private val channelRows = mutableListOf() override fun onFinishInflate() { super.onFinishInflate() @@ -58,6 +63,19 @@ class ChannelEditorListView(c: Context, attrs: AttributeSet) : LinearLayout(c, a appControlRow = findViewById(R.id.app_control) } + /** + * Play a highlight animation for the given channel (it really should exist but this will just + * fail silently if it doesn't) + */ + fun highlightChannel(channel: NotificationChannel) { + Assert.isMainThread() + for (row in channelRows) { + if (row.channel == channel) { + row.playHighlight() + } + } + } + private fun updateRows() { val enabled = controller.areAppNotificationsEnabled() @@ -83,13 +101,10 @@ class ChannelEditorListView(c: Context, attrs: AttributeSet) : LinearLayout(c, a TransitionManager.beginDelayedTransition(this, transition) // Remove any rows - val n = childCount - for (i in n.downTo(0)) { - val child = getChildAt(i) - if (child is ChannelRow) { - removeView(child) - } + for (row in channelRows) { + removeView(row) } + channelRows.clear() updateAppControlRow(enabled) @@ -105,6 +120,8 @@ class ChannelEditorListView(c: Context, attrs: AttributeSet) : LinearLayout(c, a val row = inflater.inflate(R.layout.notif_half_shelf_row, null) as ChannelRow row.controller = controller row.channel = channel + + channelRows.add(row) addView(row) } @@ -140,8 +157,14 @@ class ChannelRow(c: Context, attrs: AttributeSet) : LinearLayout(c, attrs) { private lateinit var channelName: TextView private lateinit var channelDescription: TextView private lateinit var switch: Switch + private val highlightColor: Int var gentle = false + init { + highlightColor = Utils.getColorAttrDefaultColor( + context, android.R.attr.colorControlHighlight) + } + var channel: NotificationChannel? = null set(newValue) { field = newValue @@ -162,6 +185,22 @@ class ChannelRow(c: Context, attrs: AttributeSet) : LinearLayout(c, attrs) { setOnClickListener { switch.toggle() } } + /** + * Play an animation that highlights this row + */ + fun playHighlight() { + // Use 0 for the start value because our background is given to us by our parent + val fadeInLoop = ValueAnimator.ofObject(ArgbEvaluator(), 0, highlightColor) + fadeInLoop.duration = 200L + fadeInLoop.addUpdateListener { animator -> + setBackgroundColor(animator.animatedValue as Int) + } + fadeInLoop.repeatMode = ValueAnimator.REVERSE + // Repeat an odd number of times to we end up normal + fadeInLoop.repeatCount = 5 + fadeInLoop.start() + } + private fun updateViews() { val nc = channel ?: return diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt index cc2f28eeafa02..64d0256287541 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt @@ -93,7 +93,7 @@ class ChannelEditorDialogControllerTest : SysuiTestCase() { controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID, setOf(channel1, channel2), appIcon, clickListener) - assertEquals(2, controller.providedChannels.size) + assertEquals(2, controller.paddedChannels.size) } @Test @@ -104,7 +104,7 @@ class ChannelEditorDialogControllerTest : SysuiTestCase() { setOf(channelDefault), appIcon, clickListener) assertEquals("No channels should be shown when there is only the miscellaneous channel", - 0, controller.providedChannels.size) + 0, controller.paddedChannels.size) } @Test @@ -126,7 +126,7 @@ class ChannelEditorDialogControllerTest : SysuiTestCase() { setOf(channel1), appIcon, clickListener) assertEquals("ChannelEditorDialog should fetch enough channels to show 4", - 4, controller.providedChannels.size) + 4, controller.paddedChannels.size) } @Test