Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e0cd5a8a authored by Jeff DeCew's avatar Jeff DeCew
Browse files

Reinflate active notifications when SHOW_NOTIFICATION_SNOOZE setting changes.

Test: atest PreparationCoordinatorTest NotifUiAdjustmentProviderTest
Fixes: 185399616
Change-Id: I2cc194ad604953933fb14c52cecb6151a7deee11
parent 02d0ac1b
Loading
Loading
Loading
Loading
+7 −5
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@ class NotifUiAdjustment internal constructor(
    val smartActions: List<Notification.Action>,
    val smartActions: List<Notification.Action>,
    val smartReplies: List<CharSequence>,
    val smartReplies: List<CharSequence>,
    val isConversation: Boolean,
    val isConversation: Boolean,
    val isSnoozeEnabled: Boolean,
    val isMinimized: Boolean,
    val isMinimized: Boolean,
    val needsRedaction: Boolean,
    val needsRedaction: Boolean,
) {
) {
@@ -42,6 +43,7 @@ class NotifUiAdjustment internal constructor(
        ): Boolean = when {
        ): Boolean = when {
            oldAdjustment === newAdjustment -> false
            oldAdjustment === newAdjustment -> false
            oldAdjustment.isConversation != newAdjustment.isConversation -> true
            oldAdjustment.isConversation != newAdjustment.isConversation -> true
            oldAdjustment.isSnoozeEnabled != newAdjustment.isSnoozeEnabled -> true
            oldAdjustment.isMinimized != newAdjustment.isMinimized -> true
            oldAdjustment.isMinimized != newAdjustment.isMinimized -> true
            oldAdjustment.needsRedaction != newAdjustment.needsRedaction -> true
            oldAdjustment.needsRedaction != newAdjustment.needsRedaction -> true
            areDifferent(oldAdjustment.smartActions, newAdjustment.smartActions) -> true
            areDifferent(oldAdjustment.smartActions, newAdjustment.smartActions) -> true
+30 −2
Original line number Original line Diff line number Diff line
@@ -16,12 +16,18 @@


package com.android.systemui.statusbar.notification.collection.inflation
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.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
import com.android.systemui.util.ListenerSet
import com.android.systemui.util.ListenerSet
import com.android.systemui.util.settings.SecureSettings
import javax.inject.Inject
import javax.inject.Inject


/**
/**
@@ -30,14 +36,23 @@ import javax.inject.Inject
 */
 */
@SysUISingleton
@SysUISingleton
class NotifUiAdjustmentProvider @Inject constructor(
class NotifUiAdjustmentProvider @Inject constructor(
    @Main private val handler: Handler,
    private val secureSettings: SecureSettings,
    private val lockscreenUserManager: NotificationLockscreenUserManager,
    private val lockscreenUserManager: NotificationLockscreenUserManager,
    private val sectionStyleProvider: SectionStyleProvider,
    private val sectionStyleProvider: SectionStyleProvider
) {
) {
    private val dirtyListeners = ListenerSet<Runnable>()
    private val dirtyListeners = ListenerSet<Runnable>()
    private var isSnoozeEnabled = false


    fun addDirtyListener(listener: Runnable) {
    fun addDirtyListener(listener: Runnable) {
        if (dirtyListeners.isEmpty()) {
        if (dirtyListeners.isEmpty()) {
            lockscreenUserManager.addNotificationStateChangedListener(notifStateChangedListener)
            lockscreenUserManager.addNotificationStateChangedListener(notifStateChangedListener)
            updateSnoozeEnabled()
            secureSettings.registerContentObserverForUser(
                SHOW_NOTIFICATION_SNOOZE,
                settingsObserver,
                UserHandle.USER_ALL
            )
        }
        }
        dirtyListeners.addIfAbsent(listener)
        dirtyListeners.addIfAbsent(listener)
    }
    }
@@ -46,6 +61,7 @@ class NotifUiAdjustmentProvider @Inject constructor(
        dirtyListeners.remove(listener)
        dirtyListeners.remove(listener)
        if (dirtyListeners.isEmpty()) {
        if (dirtyListeners.isEmpty()) {
            lockscreenUserManager.removeNotificationStateChangedListener(notifStateChangedListener)
            lockscreenUserManager.removeNotificationStateChangedListener(notifStateChangedListener)
            secureSettings.unregisterContentObserver(settingsObserver)
        }
        }
    }
    }


@@ -54,6 +70,17 @@ class NotifUiAdjustmentProvider @Inject constructor(
            dirtyListeners.forEach(Runnable::run)
            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 {
    private fun isEntryMinimized(entry: NotificationEntry): Boolean {
        val section = entry.section ?: error("Entry must have a section to determine if minimized")
        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")
        val parent = entry.parent ?: error("Entry must have a parent to determine if minimized")
@@ -73,6 +100,7 @@ class NotifUiAdjustmentProvider @Inject constructor(
        smartActions = entry.ranking.smartActions,
        smartActions = entry.ranking.smartActions,
        smartReplies = entry.ranking.smartReplies,
        smartReplies = entry.ranking.smartReplies,
        isConversation = entry.ranking.isConversation,
        isConversation = entry.ranking.isConversation,
        isSnoozeEnabled = isSnoozeEnabled,
        isMinimized = isEntryMinimized(entry),
        isMinimized = isEntryMinimized(entry),
        needsRedaction = lockscreenUserManager.needsRedaction(entry),
        needsRedaction = lockscreenUserManager.needsRedaction(entry),
    )
    )
+9 −2
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@ import static org.mockito.Mockito.when;


import static java.util.Objects.requireNonNull;
import static java.util.Objects.requireNonNull;


import android.os.Handler;
import android.os.RemoteException;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
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.provider.SectionStyleProvider;
import com.android.systemui.statusbar.notification.collection.render.NotifViewBarn;
import com.android.systemui.statusbar.notification.collection.render.NotifViewBarn;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
import com.android.systemui.util.settings.SecureSettings;


import org.junit.Before;
import org.junit.Before;
import org.junit.Test;
import org.junit.Test;
@@ -97,6 +99,8 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
    @Mock private IStatusBarService mService;
    @Mock private IStatusBarService mService;
    @Mock private BindEventManagerImpl mBindEventManagerImpl;
    @Mock private BindEventManagerImpl mBindEventManagerImpl;
    @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
    @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
    @Mock private Handler mHandler;
    @Mock private SecureSettings mSecureSettings;
    @Spy private FakeNotifInflater mNotifInflater = new FakeNotifInflater();
    @Spy private FakeNotifInflater mNotifInflater = new FakeNotifInflater();
    private final SectionStyleProvider mSectionStyleProvider = new SectionStyleProvider();
    private final SectionStyleProvider mSectionStyleProvider = new SectionStyleProvider();


@@ -110,8 +114,11 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
    @Before
    @Before
    public void setUp() {
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        MockitoAnnotations.initMocks(this);
        mAdjustmentProvider =
        mAdjustmentProvider = new NotifUiAdjustmentProvider(
            new NotifUiAdjustmentProvider(mLockscreenUserManager, mSectionStyleProvider);
                mHandler,
                mSecureSettings,
                mLockscreenUserManager,
                mSectionStyleProvider);
        mEntry = getNotificationEntryBuilder().setParent(ROOT_ENTRY).build();
        mEntry = getNotificationEntryBuilder().setParent(ROOT_ENTRY).build();
        mInflationError = new Exception(TEST_MESSAGE);
        mInflationError = new Exception(TEST_MESSAGE);
        mErrorManager = new NotifInflationErrorManager();
        mErrorManager = new NotifInflationErrorManager();
+88 −1
Original line number Original line Diff line number Diff line
/*
 * 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
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.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.NotificationLockscreenUserManager
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.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.mock
import com.android.systemui.util.mockito.withArgCaptor
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.Test
import org.junit.runner.RunWith
import org.junit.runner.RunWith
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.verify
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.`when` as whenever


@SmallTest
@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWith(AndroidTestingRunner::class)
@@ -18,12 +49,39 @@ import org.mockito.Mockito.verify
class NotifUiAdjustmentProviderTest : SysuiTestCase() {
class NotifUiAdjustmentProviderTest : SysuiTestCase() {
    private val lockscreenUserManager: NotificationLockscreenUserManager = mock()
    private val lockscreenUserManager: NotificationLockscreenUserManager = mock()
    private val sectionStyleProvider: SectionStyleProvider = 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(
    private val adjustmentProvider = NotifUiAdjustmentProvider(
        handler,
        secureSettings,
        lockscreenUserManager,
        lockscreenUserManager,
        sectionStyleProvider,
        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
    @Test
    fun notifLockscreenStateChangeWillNotifDirty() {
    fun notifLockscreenStateChangeWillNotifDirty() {
        val dirtyListener = mock<Runnable>()
        val dirtyListener = mock<Runnable>()
@@ -33,6 +91,35 @@ class NotifUiAdjustmentProviderTest : SysuiTestCase() {
                verify(lockscreenUserManager).addNotificationStateChangedListener(capture())
                verify(lockscreenUserManager).addNotificationStateChangedListener(capture())
            }
            }
        notifLocksreenStateChangeListener.onNotificationStateChanged()
        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)
    }
    }
}
}