blob: 2ee31265ff7bb145a07dd76a5da1368d901a5bb9 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.collection.coordinator
import android.app.Notification.GROUP_ALERT_ALL
import android.app.Notification.GROUP_ALERT_SUMMARY
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.statusbar.NotificationRemoteInputManager
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
import com.android.systemui.statusbar.notification.collection.render.NodeController
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider
import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback
import com.android.systemui.statusbar.phone.NotificationGroupTestHelper
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.withArgCaptor
import com.android.systemui.util.time.FakeSystemClock
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyString
import org.mockito.BDDMockito.given
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import java.util.ArrayList
import java.util.function.Consumer
import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
class HeadsUpCoordinatorTest : SysuiTestCase() {
private lateinit var mCoordinator: HeadsUpCoordinator
// captured listeners and pluggables:
private lateinit var mCollectionListener: NotifCollectionListener
private lateinit var mNotifPromoter: NotifPromoter
private lateinit var mNotifLifetimeExtender: NotifLifetimeExtender
private lateinit var mBeforeTransformGroupsListener: OnBeforeTransformGroupsListener
private lateinit var mBeforeFinalizeFilterListener: OnBeforeFinalizeFilterListener
private lateinit var mOnHeadsUpChangedListener: OnHeadsUpChangedListener
private lateinit var mNotifSectioner: NotifSectioner
private lateinit var mActionPressListener: Consumer<NotificationEntry>
private val mNotifPipeline: NotifPipeline = mock()
private val mLogger = HeadsUpCoordinatorLogger(logcatLogBuffer(), verbose = true)
private val mHeadsUpManager: HeadsUpManager = mock()
private val mHeadsUpViewBinder: HeadsUpViewBinder = mock()
private val mNotificationInterruptStateProvider: NotificationInterruptStateProvider = mock()
private val mRemoteInputManager: NotificationRemoteInputManager = mock()
private val mEndLifetimeExtension: OnEndLifetimeExtensionCallback = mock()
private val mHeaderController: NodeController = mock()
private lateinit var mEntry: NotificationEntry
private lateinit var mGroupSummary: NotificationEntry
private lateinit var mGroupPriority: NotificationEntry
private lateinit var mGroupSibling1: NotificationEntry
private lateinit var mGroupSibling2: NotificationEntry
private lateinit var mGroupChild1: NotificationEntry
private lateinit var mGroupChild2: NotificationEntry
private lateinit var mGroupChild3: NotificationEntry
private val mSystemClock = FakeSystemClock()
private val mExecutor = FakeExecutor(mSystemClock)
private val mHuns: ArrayList<NotificationEntry> = ArrayList()
private lateinit var mHelper: NotificationGroupTestHelper
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
mHelper = NotificationGroupTestHelper(mContext)
mCoordinator = HeadsUpCoordinator(
mLogger,
mSystemClock,
mHeadsUpManager,
mHeadsUpViewBinder,
mNotificationInterruptStateProvider,
mRemoteInputManager,
mHeaderController,
mExecutor)
mCoordinator.attach(mNotifPipeline)
// capture arguments:
mCollectionListener = withArgCaptor {
verify(mNotifPipeline).addCollectionListener(capture())
}
mNotifPromoter = withArgCaptor {
verify(mNotifPipeline).addPromoter(capture())
}
mNotifLifetimeExtender = withArgCaptor {
verify(mNotifPipeline).addNotificationLifetimeExtender(capture())
}
mBeforeTransformGroupsListener = withArgCaptor {
verify(mNotifPipeline).addOnBeforeTransformGroupsListener(capture())
}
mBeforeFinalizeFilterListener = withArgCaptor {
verify(mNotifPipeline).addOnBeforeFinalizeFilterListener(capture())
}
mOnHeadsUpChangedListener = withArgCaptor {
verify(mHeadsUpManager).addListener(capture())
}
mActionPressListener = withArgCaptor {
verify(mRemoteInputManager).addActionPressListener(capture())
}
given(mHeadsUpManager.allEntries).willAnswer { mHuns.stream() }
given(mHeadsUpManager.isAlerting(anyString())).willAnswer { invocation ->
val key = invocation.getArgument<String>(0)
mHuns.any { entry -> entry.key == key }
}
given(mHeadsUpManager.canRemoveImmediately(anyString())).willAnswer { invocation ->
val key = invocation.getArgument<String>(0)
!mHuns.any { entry -> entry.key == key }
}
whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L)
mNotifSectioner = mCoordinator.sectioner
mNotifLifetimeExtender.setCallback(mEndLifetimeExtension)
mEntry = NotificationEntryBuilder().build()
// Same summary we can use for either set of children
mGroupSummary = mHelper.createSummaryNotification(GROUP_ALERT_ALL, 0, "summary", 500)
// One set of children with GROUP_ALERT_SUMMARY
mGroupPriority = mHelper.createChildNotification(GROUP_ALERT_SUMMARY, 0, "priority", 400)
mGroupSibling1 = mHelper.createChildNotification(GROUP_ALERT_SUMMARY, 1, "sibling", 300)
mGroupSibling2 = mHelper.createChildNotification(GROUP_ALERT_SUMMARY, 2, "sibling", 200)
// Another set of children with GROUP_ALERT_ALL
mGroupChild1 = mHelper.createChildNotification(GROUP_ALERT_ALL, 1, "child", 350)
mGroupChild2 = mHelper.createChildNotification(GROUP_ALERT_ALL, 2, "child", 250)
mGroupChild3 = mHelper.createChildNotification(GROUP_ALERT_ALL, 3, "child", 150)
}
@Test
fun testCancelStickyNotification() {
whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
addHUN(mEntry)
whenever(mHeadsUpManager.canRemoveImmediately(anyString())).thenReturn(false, true)
whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 0L)
assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
mExecutor.advanceClockToLast()
mExecutor.runAllReady()
verify(mHeadsUpManager, times(0)).removeNotification(anyString(), eq(false))
verify(mHeadsUpManager, times(1)).removeNotification(anyString(), eq(true))
}
@Test
fun testCancelAndReAddStickyNotification() {
whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
addHUN(mEntry)
whenever(mHeadsUpManager.canRemoveImmediately(anyString())).thenReturn(false, true, false)
whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L)
assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
addHUN(mEntry)
assertFalse(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
mExecutor.advanceClockToLast()
mExecutor.runAllReady()
assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
verify(mHeadsUpManager, times(0)).removeNotification(anyString(), eq(false))
verify(mHeadsUpManager, times(0)).removeNotification(anyString(), eq(true))
}
@Test
fun hunNotRemovedWhenExtensionCancelled() {
whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
addHUN(mEntry)
whenever(mHeadsUpManager.canRemoveImmediately(anyString())).thenReturn(false)
whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L)
assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
mNotifLifetimeExtender.cancelLifetimeExtension(mEntry)
mExecutor.advanceClockToLast()
mExecutor.runAllReady()
verify(mHeadsUpManager, times(0)).removeNotification(anyString(), any())
}
@Test
fun hunExtensionCancelledWhenHunActionPressed() {
whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
addHUN(mEntry)
whenever(mHeadsUpManager.canRemoveImmediately(anyString())).thenReturn(false)
whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L)
assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
mActionPressListener.accept(mEntry)
mExecutor.advanceClockToLast()
mExecutor.runAllReady()
verify(mHeadsUpManager, times(1)).removeNotification(eq(mEntry.key), eq(true))
}
@Test
fun testCancelUpdatedStickyNotification() {
whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true)
addHUN(mEntry)
whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 500L)
assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
addHUN(mEntry)
mExecutor.advanceClockToLast()
mExecutor.runAllReady()
verify(mHeadsUpManager, times(0)).removeNotification(anyString(), eq(false))
verify(mHeadsUpManager, times(0)).removeNotification(anyString(), eq(true))
}
@Test
fun testCancelNotification() {
whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(false)
addHUN(mEntry)
whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 500L)
assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0))
mExecutor.advanceClockToLast()
mExecutor.runAllReady()
verify(mHeadsUpManager, times(1)).removeNotification(anyString(), eq(false))
verify(mHeadsUpManager, times(0)).removeNotification(anyString(), eq(true))
}
@Test
fun testPromotesAddedHUN() {
// GIVEN the current entry should heads up
whenever(mNotificationInterruptStateProvider.shouldHeadsUp(mEntry)).thenReturn(true)
// WHEN the notification is added but not yet binding
mCollectionListener.onEntryAdded(mEntry)
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mEntry), any())
// THEN only promote mEntry
assertTrue(mNotifPromoter.shouldPromoteToTopLevel(mEntry))
}
@Test
fun testPromotesBindingHUN() {
// GIVEN the current entry should heads up
whenever(mNotificationInterruptStateProvider.shouldHeadsUp(mEntry)).thenReturn(true)
// WHEN the notification started binding on the previous run
mCollectionListener.onEntryAdded(mEntry)
mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(mEntry))
mBeforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(mEntry))
verify(mHeadsUpViewBinder).bindHeadsUpView(eq(mEntry), any())
// THEN only promote mEntry
assertTrue(mNotifPromoter.shouldPromoteToTopLevel(mEntry))
}
@Test
fun testPromotesCurrentHUN() {
// GIVEN the current HUN is set to mEntry
addHUN(mEntry)
// THEN only promote the current HUN, mEntry
assertTrue(mNotifPromoter.shouldPromoteToTopLevel(mEntry))
assertFalse(mNotifPromoter.shouldPromoteToTopLevel(NotificationEntryBuilder()
.setPkg("test-package2")
.build()))
}
@Test
fun testIncludeInSectionCurrentHUN() {
// GIVEN the current HUN is set to mEntry
addHUN(mEntry)
// THEN only section the current HUN, mEntry
assertTrue(mNotifSectioner.isInSection(mEntry))
assertFalse(mNotifSectioner.isInSection(NotificationEntryBuilder()
.setPkg("test-package")
.build()))
}
@Test
fun testLifetimeExtendsCurrentHUN() {
// GIVEN there is a HUN, mEntry
addHUN(mEntry)
// THEN only the current HUN, mEntry, should be lifetimeExtended
assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, /* cancellationReason */ 0))
assertFalse(mNotifLifetimeExtender.maybeExtendLifetime(
NotificationEntryBuilder()
.setPkg("test-package")
.build(), /* cancellationReason */ 0))
}
@Test
fun testShowHUNOnInflationFinished() {
// WHEN a notification should HUN and its inflation is finished
whenever(mNotificationInterruptStateProvider.shouldHeadsUp(mEntry)).thenReturn(true)
mCollectionListener.onEntryAdded(mEntry)
mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(mEntry))
mBeforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(mEntry))
verify(mHeadsUpManager, never()).showNotification(mEntry)
withArgCaptor<BindCallback> {
verify(mHeadsUpViewBinder).bindHeadsUpView(eq(mEntry), capture())
}.onBindFinished(mEntry)
// THEN we tell the HeadsUpManager to show the notification
verify(mHeadsUpManager).showNotification(mEntry)
}
@Test
fun testNoHUNOnInflationFinished() {
// WHEN a notification shouldn't HUN and its inflation is finished
whenever(mNotificationInterruptStateProvider.shouldHeadsUp(mEntry)).thenReturn(false)
mCollectionListener.onEntryAdded(mEntry)
mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(mEntry))
mBeforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(mEntry))
// THEN we never bind the heads up view or tell HeadsUpManager to show the notification
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mEntry), any())
verify(mHeadsUpManager, never()).showNotification(mEntry)
}
@Test
fun testOnEntryRemovedRemovesHeadsUpNotification() {
// GIVEN the current HUN is mEntry
addHUN(mEntry)
// WHEN mEntry is removed from the notification collection
mCollectionListener.onEntryRemoved(mEntry, /* cancellation reason */ 0)
whenever(mRemoteInputManager.isSpinning(any())).thenReturn(false)
// THEN heads up manager should remove the entry
verify(mHeadsUpManager).removeNotification(mEntry.key, false)
}
private fun addHUN(entry: NotificationEntry) {
mHuns.add(entry)
whenever(mHeadsUpManager.topEntry).thenReturn(entry)
mOnHeadsUpChangedListener.onHeadsUpStateChanged(entry, true)
mNotifLifetimeExtender.cancelLifetimeExtension(entry)
}
@Test
fun testTransferIsolatedChildAlert_withGroupAlertSummary() {
setShouldHeadsUp(mGroupSummary)
whenever(mNotifPipeline.allNotifs).thenReturn(listOf(mGroupSummary, mGroupSibling1))
mCollectionListener.onEntryAdded(mGroupSummary)
mCollectionListener.onEntryAdded(mGroupSibling1)
mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(mGroupSibling1))
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(any(), any())
mBeforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(mGroupSibling1))
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSummary), any())
finishBind(mGroupSibling1)
verify(mHeadsUpManager, never()).showNotification(mGroupSummary)
verify(mHeadsUpManager).showNotification(mGroupSibling1)
}
@Test
fun testTransferIsolatedChildAlert_withGroupAlertAll() {
setShouldHeadsUp(mGroupSummary)
whenever(mNotifPipeline.allNotifs).thenReturn(listOf(mGroupSummary, mGroupChild1))
mCollectionListener.onEntryAdded(mGroupSummary)
mCollectionListener.onEntryAdded(mGroupChild1)
mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(mGroupChild1))
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(any(), any())
mBeforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(mGroupChild1))
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSummary), any())
finishBind(mGroupChild1)
verify(mHeadsUpManager, never()).showNotification(mGroupSummary)
verify(mHeadsUpManager).showNotification(mGroupChild1)
}
@Test
fun testTransferTwoIsolatedChildAlert_withGroupAlertSummary() {
// WHEN a notification should HUN and its inflation is finished
setShouldHeadsUp(mGroupSummary)
whenever(mNotifPipeline.allNotifs)
.thenReturn(listOf(mGroupSummary, mGroupSibling1, mGroupSibling2, mGroupPriority))
mCollectionListener.onEntryAdded(mGroupSummary)
mCollectionListener.onEntryAdded(mGroupSibling1)
mCollectionListener.onEntryAdded(mGroupSibling2)
val entryList = listOf(mGroupSibling1, mGroupSibling2)
mBeforeTransformGroupsListener.onBeforeTransformGroups(entryList)
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(any(), any())
mBeforeFinalizeFilterListener.onBeforeFinalizeFilter(entryList)
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSummary), any())
finishBind(mGroupSibling1)
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSibling2), any())
// THEN we tell the HeadsUpManager to show the notification
verify(mHeadsUpManager, never()).showNotification(mGroupSummary)
verify(mHeadsUpManager).showNotification(mGroupSibling1)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling2)
}
@Test
fun testTransferTwoIsolatedChildAlert_withGroupAlertAll() {
// WHEN a notification should HUN and its inflation is finished
setShouldHeadsUp(mGroupSummary)
whenever(mNotifPipeline.allNotifs)
.thenReturn(listOf(mGroupSummary, mGroupChild1, mGroupChild2, mGroupPriority))
mCollectionListener.onEntryAdded(mGroupSummary)
mCollectionListener.onEntryAdded(mGroupChild1)
mCollectionListener.onEntryAdded(mGroupChild2)
val entryList = listOf(mGroupChild1, mGroupChild2)
mBeforeTransformGroupsListener.onBeforeTransformGroups(entryList)
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(any(), any())
mBeforeFinalizeFilterListener.onBeforeFinalizeFilter(entryList)
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSummary), any())
finishBind(mGroupChild1)
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupChild2), any())
// THEN we tell the HeadsUpManager to show the notification
verify(mHeadsUpManager, never()).showNotification(mGroupSummary)
verify(mHeadsUpManager).showNotification(mGroupChild1)
verify(mHeadsUpManager, never()).showNotification(mGroupChild2)
}
@Test
fun testTransferToPriorityOnAddWithTwoSiblings() {
// WHEN a notification should HUN and its inflation is finished
setShouldHeadsUp(mGroupSummary)
whenever(mNotifPipeline.allNotifs)
.thenReturn(listOf(mGroupSummary, mGroupSibling1, mGroupSibling2, mGroupPriority))
mCollectionListener.onEntryAdded(mGroupSummary)
mCollectionListener.onEntryAdded(mGroupPriority)
mCollectionListener.onEntryAdded(mGroupSibling1)
mCollectionListener.onEntryAdded(mGroupSibling2)
val beforeTransformGroup = GroupEntryBuilder()
.setSummary(mGroupSummary)
.setChildren(listOf(mGroupSibling1, mGroupPriority, mGroupSibling2))
.build()
mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(beforeTransformGroup))
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(any(), any())
val afterTransformGroup = GroupEntryBuilder()
.setSummary(mGroupSummary)
.setChildren(listOf(mGroupSibling1, mGroupSibling2))
.build()
mBeforeFinalizeFilterListener
.onBeforeFinalizeFilter(listOf(mGroupPriority, afterTransformGroup))
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSummary), any())
finishBind(mGroupPriority)
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSibling1), any())
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSibling2), any())
// THEN we tell the HeadsUpManager to show the notification
verify(mHeadsUpManager, never()).showNotification(mGroupSummary)
verify(mHeadsUpManager).showNotification(mGroupPriority)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling1)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling2)
}
@Test
fun testTransferToPriorityOnUpdateWithTwoSiblings() {
setShouldHeadsUp(mGroupSummary)
whenever(mNotifPipeline.allNotifs)
.thenReturn(listOf(mGroupSummary, mGroupSibling1, mGroupSibling2, mGroupPriority))
mCollectionListener.onEntryUpdated(mGroupSummary)
mCollectionListener.onEntryUpdated(mGroupPriority)
mCollectionListener.onEntryUpdated(mGroupSibling1)
mCollectionListener.onEntryUpdated(mGroupSibling2)
val beforeTransformGroup = GroupEntryBuilder()
.setSummary(mGroupSummary)
.setChildren(listOf(mGroupSibling1, mGroupPriority, mGroupSibling2))
.build()
mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(beforeTransformGroup))
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(any(), any())
val afterTransformGroup = GroupEntryBuilder()
.setSummary(mGroupSummary)
.setChildren(listOf(mGroupSibling1, mGroupSibling2))
.build()
mBeforeFinalizeFilterListener
.onBeforeFinalizeFilter(listOf(mGroupPriority, afterTransformGroup))
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSummary), any())
finishBind(mGroupPriority)
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSibling1), any())
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSibling2), any())
verify(mHeadsUpManager, never()).showNotification(mGroupSummary)
verify(mHeadsUpManager).showNotification(mGroupPriority)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling1)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling2)
}
@Test
fun testTransferToPriorityOnUpdateWithTwoNonUpdatedSiblings() {
setShouldHeadsUp(mGroupSummary)
whenever(mNotifPipeline.allNotifs)
.thenReturn(listOf(mGroupSummary, mGroupSibling1, mGroupSibling2, mGroupPriority))
mCollectionListener.onEntryUpdated(mGroupSummary)
mCollectionListener.onEntryUpdated(mGroupPriority)
val beforeTransformGroup = GroupEntryBuilder()
.setSummary(mGroupSummary)
.setChildren(listOf(mGroupSibling1, mGroupPriority, mGroupSibling2))
.build()
mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(beforeTransformGroup))
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(any(), any())
val afterTransformGroup = GroupEntryBuilder()
.setSummary(mGroupSummary)
.setChildren(listOf(mGroupSibling1, mGroupSibling2))
.build()
mBeforeFinalizeFilterListener
.onBeforeFinalizeFilter(listOf(mGroupPriority, afterTransformGroup))
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSummary), any())
finishBind(mGroupPriority)
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSibling1), any())
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSibling2), any())
verify(mHeadsUpManager, never()).showNotification(mGroupSummary)
verify(mHeadsUpManager).showNotification(mGroupPriority)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling1)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling2)
}
@Test
fun testNoTransferToPriorityOnUpdateOfTwoSiblings() {
setShouldHeadsUp(mGroupSummary)
whenever(mNotifPipeline.allNotifs)
.thenReturn(listOf(mGroupSummary, mGroupSibling1, mGroupSibling2, mGroupPriority))
mCollectionListener.onEntryUpdated(mGroupSummary)
mCollectionListener.onEntryUpdated(mGroupSibling1)
mCollectionListener.onEntryUpdated(mGroupSibling2)
val beforeTransformGroup = GroupEntryBuilder()
.setSummary(mGroupSummary)
.setChildren(listOf(mGroupSibling1, mGroupPriority, mGroupSibling2))
.build()
mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(beforeTransformGroup))
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(any(), any())
val afterTransformGroup = GroupEntryBuilder()
.setSummary(mGroupSummary)
.setChildren(listOf(mGroupSibling1, mGroupSibling2))
.build()
mBeforeFinalizeFilterListener
.onBeforeFinalizeFilter(listOf(mGroupPriority, afterTransformGroup))
finishBind(mGroupSummary)
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupPriority), any())
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSibling1), any())
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSibling2), any())
verify(mHeadsUpManager).showNotification(mGroupSummary)
verify(mHeadsUpManager, never()).showNotification(mGroupPriority)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling1)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling2)
}
@Test
fun testNoTransferTwoChildAlert_withGroupAlertSummary() {
setShouldHeadsUp(mGroupSummary)
whenever(mNotifPipeline.allNotifs)
.thenReturn(listOf(mGroupSummary, mGroupSibling1, mGroupSibling2))
mCollectionListener.onEntryAdded(mGroupSummary)
mCollectionListener.onEntryAdded(mGroupSibling1)
mCollectionListener.onEntryAdded(mGroupSibling2)
val groupEntry = GroupEntryBuilder()
.setSummary(mGroupSummary)
.setChildren(listOf(mGroupSibling1, mGroupSibling2))
.build()
mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(groupEntry))
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(any(), any())
mBeforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(groupEntry))
finishBind(mGroupSummary)
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSibling1), any())
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSibling2), any())
verify(mHeadsUpManager).showNotification(mGroupSummary)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling1)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling2)
}
@Test
fun testNoTransferTwoChildAlert_withGroupAlertAll() {
setShouldHeadsUp(mGroupSummary)
whenever(mNotifPipeline.allNotifs)
.thenReturn(listOf(mGroupSummary, mGroupChild1, mGroupChild2))
mCollectionListener.onEntryAdded(mGroupSummary)
mCollectionListener.onEntryAdded(mGroupChild1)
mCollectionListener.onEntryAdded(mGroupChild2)
val groupEntry = GroupEntryBuilder()
.setSummary(mGroupSummary)
.setChildren(listOf(mGroupChild1, mGroupChild2))
.build()
mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(groupEntry))
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(any(), any())
mBeforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(groupEntry))
finishBind(mGroupSummary)
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupChild1), any())
verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupChild2), any())
verify(mHeadsUpManager).showNotification(mGroupSummary)
verify(mHeadsUpManager, never()).showNotification(mGroupChild1)
verify(mHeadsUpManager, never()).showNotification(mGroupChild2)
}
private fun setShouldHeadsUp(entry: NotificationEntry, should: Boolean = true) {
whenever(mNotificationInterruptStateProvider.shouldHeadsUp(entry)).thenReturn(should)
}
private fun finishBind(entry: NotificationEntry) {
verify(mHeadsUpManager, never()).showNotification(entry)
withArgCaptor<BindCallback> {
verify(mHeadsUpViewBinder).bindHeadsUpView(eq(entry), capture())
}.onBindFinished(entry)
}
}