Reinflate active notifications when SHOW_NOTIFICATION_SNOOZE setting changes.
Test: atest PreparationCoordinatorTest NotifUiAdjustmentProviderTest Fixes: 185399616 Change-Id: I2cc194ad604953933fb14c52cecb6151a7deee11
This commit is contained in:
@@ -31,6 +31,7 @@ class NotifUiAdjustment internal constructor(
|
||||
val smartActions: List<Notification.Action>,
|
||||
val smartReplies: List<CharSequence>,
|
||||
val isConversation: Boolean,
|
||||
val isSnoozeEnabled: Boolean,
|
||||
val isMinimized: Boolean,
|
||||
val needsRedaction: Boolean,
|
||||
) {
|
||||
@@ -42,6 +43,7 @@ class NotifUiAdjustment internal constructor(
|
||||
): Boolean = when {
|
||||
oldAdjustment === newAdjustment -> false
|
||||
oldAdjustment.isConversation != newAdjustment.isConversation -> true
|
||||
oldAdjustment.isSnoozeEnabled != newAdjustment.isSnoozeEnabled -> true
|
||||
oldAdjustment.isMinimized != newAdjustment.isMinimized -> true
|
||||
oldAdjustment.needsRedaction != newAdjustment.needsRedaction -> true
|
||||
areDifferent(oldAdjustment.smartActions, newAdjustment.smartActions) -> true
|
||||
@@ -57,9 +59,9 @@ class NotifUiAdjustment internal constructor(
|
||||
first.size != second.size -> true
|
||||
else -> first.asSequence().zip(second.asSequence()).any {
|
||||
(!TextUtils.equals(it.first.title, it.second.title)) ||
|
||||
(areDifferent(it.first.getIcon(), it.second.getIcon())) ||
|
||||
(it.first.actionIntent != it.second.actionIntent) ||
|
||||
(areDifferent(it.first.remoteInputs, it.second.remoteInputs))
|
||||
(areDifferent(it.first.getIcon(), it.second.getIcon())) ||
|
||||
(it.first.actionIntent != it.second.actionIntent) ||
|
||||
(areDifferent(it.first.remoteInputs, it.second.remoteInputs))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +80,7 @@ class NotifUiAdjustment internal constructor(
|
||||
first.size != second.size -> true
|
||||
else -> first.asSequence().zip(second.asSequence()).any {
|
||||
(!TextUtils.equals(it.first.label, it.second.label)) ||
|
||||
(areDifferent(it.first.choices, it.second.choices))
|
||||
(areDifferent(it.first.choices, it.second.choices))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,4 +96,4 @@ class NotifUiAdjustment internal constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,18 @@
|
||||
|
||||
package com.android.systemui.statusbar.notification.collection.inflation
|
||||
|
||||
import android.database.ContentObserver
|
||||
import android.os.Handler
|
||||
import android.os.UserHandle
|
||||
import android.provider.Settings.Secure.SHOW_NOTIFICATION_SNOOZE
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||
import com.android.systemui.statusbar.notification.collection.GroupEntry
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry
|
||||
import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
|
||||
import com.android.systemui.util.ListenerSet
|
||||
import com.android.systemui.util.settings.SecureSettings
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
@@ -30,14 +36,23 @@ import javax.inject.Inject
|
||||
*/
|
||||
@SysUISingleton
|
||||
class NotifUiAdjustmentProvider @Inject constructor(
|
||||
@Main private val handler: Handler,
|
||||
private val secureSettings: SecureSettings,
|
||||
private val lockscreenUserManager: NotificationLockscreenUserManager,
|
||||
private val sectionStyleProvider: SectionStyleProvider,
|
||||
private val sectionStyleProvider: SectionStyleProvider
|
||||
) {
|
||||
private val dirtyListeners = ListenerSet<Runnable>()
|
||||
private var isSnoozeEnabled = false
|
||||
|
||||
fun addDirtyListener(listener: Runnable) {
|
||||
if (dirtyListeners.isEmpty()) {
|
||||
lockscreenUserManager.addNotificationStateChangedListener(notifStateChangedListener)
|
||||
updateSnoozeEnabled()
|
||||
secureSettings.registerContentObserverForUser(
|
||||
SHOW_NOTIFICATION_SNOOZE,
|
||||
settingsObserver,
|
||||
UserHandle.USER_ALL
|
||||
)
|
||||
}
|
||||
dirtyListeners.addIfAbsent(listener)
|
||||
}
|
||||
@@ -46,6 +61,7 @@ class NotifUiAdjustmentProvider @Inject constructor(
|
||||
dirtyListeners.remove(listener)
|
||||
if (dirtyListeners.isEmpty()) {
|
||||
lockscreenUserManager.removeNotificationStateChangedListener(notifStateChangedListener)
|
||||
secureSettings.unregisterContentObserver(settingsObserver)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +70,17 @@ class NotifUiAdjustmentProvider @Inject constructor(
|
||||
dirtyListeners.forEach(Runnable::run)
|
||||
}
|
||||
|
||||
private val settingsObserver = object : ContentObserver(handler) {
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
updateSnoozeEnabled()
|
||||
dirtyListeners.forEach(Runnable::run)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSnoozeEnabled() {
|
||||
isSnoozeEnabled = secureSettings.getInt(SHOW_NOTIFICATION_SNOOZE, 0) == 1
|
||||
}
|
||||
|
||||
private fun isEntryMinimized(entry: NotificationEntry): Boolean {
|
||||
val section = entry.section ?: error("Entry must have a section to determine if minimized")
|
||||
val parent = entry.parent ?: error("Entry must have a parent to determine if minimized")
|
||||
@@ -73,7 +100,8 @@ class NotifUiAdjustmentProvider @Inject constructor(
|
||||
smartActions = entry.ranking.smartActions,
|
||||
smartReplies = entry.ranking.smartReplies,
|
||||
isConversation = entry.ranking.isConversation,
|
||||
isSnoozeEnabled = isSnoozeEnabled,
|
||||
isMinimized = isEntryMinimized(entry),
|
||||
needsRedaction = lockscreenUserManager.needsRedaction(entry),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
@@ -59,6 +60,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.No
|
||||
import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider;
|
||||
import com.android.systemui.statusbar.notification.collection.render.NotifViewBarn;
|
||||
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
|
||||
import com.android.systemui.util.settings.SecureSettings;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -97,6 +99,8 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
|
||||
@Mock private IStatusBarService mService;
|
||||
@Mock private BindEventManagerImpl mBindEventManagerImpl;
|
||||
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
|
||||
@Mock private Handler mHandler;
|
||||
@Mock private SecureSettings mSecureSettings;
|
||||
@Spy private FakeNotifInflater mNotifInflater = new FakeNotifInflater();
|
||||
private final SectionStyleProvider mSectionStyleProvider = new SectionStyleProvider();
|
||||
|
||||
@@ -110,8 +114,11 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mAdjustmentProvider =
|
||||
new NotifUiAdjustmentProvider(mLockscreenUserManager, mSectionStyleProvider);
|
||||
mAdjustmentProvider = new NotifUiAdjustmentProvider(
|
||||
mHandler,
|
||||
mSecureSettings,
|
||||
mLockscreenUserManager,
|
||||
mSectionStyleProvider);
|
||||
mEntry = getNotificationEntryBuilder().setParent(ROOT_ENTRY).build();
|
||||
mInflationError = new Exception(TEST_MESSAGE);
|
||||
mErrorManager = new NotifInflationErrorManager();
|
||||
|
||||
@@ -1,16 +1,47 @@
|
||||
/*
|
||||
* 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.inflation
|
||||
|
||||
import android.database.ContentObserver
|
||||
import android.os.Handler
|
||||
import android.provider.Settings.Secure.SHOW_NOTIFICATION_SNOOZE
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper.RunWithLooper
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||
import com.android.systemui.statusbar.notification.collection.GroupEntry
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
|
||||
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
|
||||
import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
|
||||
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.settings.FakeSettings
|
||||
import com.android.systemui.util.settings.SecureSettings
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.Mockito.inOrder
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@@ -18,12 +49,39 @@ import org.mockito.Mockito.verify
|
||||
class NotifUiAdjustmentProviderTest : SysuiTestCase() {
|
||||
private val lockscreenUserManager: NotificationLockscreenUserManager = mock()
|
||||
private val sectionStyleProvider: SectionStyleProvider = mock()
|
||||
private val handler: Handler = mock()
|
||||
private val secureSettings: SecureSettings = mock()
|
||||
private val uri = FakeSettings().getUriFor(SHOW_NOTIFICATION_SNOOZE)
|
||||
private val dirtyListener: Runnable = mock()
|
||||
|
||||
private val section = NotifSection(mock(), 0)
|
||||
private val entry = NotificationEntryBuilder()
|
||||
.setSection(section)
|
||||
.setParent(GroupEntry.ROOT_ENTRY)
|
||||
.build()
|
||||
|
||||
private lateinit var contentObserver: ContentObserver
|
||||
|
||||
private val adjustmentProvider = NotifUiAdjustmentProvider(
|
||||
handler,
|
||||
secureSettings,
|
||||
lockscreenUserManager,
|
||||
sectionStyleProvider,
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
verifyNoMoreInteractions(secureSettings)
|
||||
adjustmentProvider.addDirtyListener(dirtyListener)
|
||||
verify(secureSettings).getInt(eq(SHOW_NOTIFICATION_SNOOZE), any())
|
||||
contentObserver = withArgCaptor {
|
||||
verify(secureSettings).registerContentObserverForUser(
|
||||
eq(SHOW_NOTIFICATION_SNOOZE), capture(), any()
|
||||
)
|
||||
}
|
||||
verifyNoMoreInteractions(secureSettings, dirtyListener)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun notifLockscreenStateChangeWillNotifDirty() {
|
||||
val dirtyListener = mock<Runnable>()
|
||||
@@ -33,6 +91,35 @@ class NotifUiAdjustmentProviderTest : SysuiTestCase() {
|
||||
verify(lockscreenUserManager).addNotificationStateChangedListener(capture())
|
||||
}
|
||||
notifLocksreenStateChangeListener.onNotificationStateChanged()
|
||||
verify(dirtyListener).run();
|
||||
verify(dirtyListener).run()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun additionalAddDoesNotRegisterAgain() {
|
||||
clearInvocations(secureSettings)
|
||||
adjustmentProvider.addDirtyListener(mock())
|
||||
verifyNoMoreInteractions(secureSettings)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onChangeWillQueryThenNotifyDirty() {
|
||||
contentObserver.onChange(false, listOf(uri), 0, 0)
|
||||
with(inOrder(secureSettings, dirtyListener)) {
|
||||
verify(secureSettings).getInt(eq(SHOW_NOTIFICATION_SNOOZE), any())
|
||||
verify(dirtyListener).run()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun changingSnoozeChangesProvidedAdjustment() {
|
||||
whenever(secureSettings.getInt(eq(SHOW_NOTIFICATION_SNOOZE), any())).thenReturn(0)
|
||||
val original = adjustmentProvider.calculateAdjustment(entry)
|
||||
assertThat(original.isSnoozeEnabled).isFalse()
|
||||
|
||||
whenever(secureSettings.getInt(eq(SHOW_NOTIFICATION_SNOOZE), any())).thenReturn(1)
|
||||
contentObserver.onChange(false, listOf(uri), 0, 0)
|
||||
val withSnoozing = adjustmentProvider.calculateAdjustment(entry)
|
||||
assertThat(withSnoozing.isSnoozeEnabled).isTrue()
|
||||
assertThat(withSnoozing).isNotEqualTo(original)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user