diff options
4 files changed, 133 insertions, 9 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt index 3475fcf7c12f..ee0b00807e27 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt @@ -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( } } } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt index 3dbcddf192c2..745d6fe1d624 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt @@ -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 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), ) -}
\ No newline at end of file +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java index 35576faef1a8..a6d3719de5cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java @@ -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(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt index 502b75996ebc..246943e3088e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt @@ -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) } } |