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

Commit 38146312 authored by Ioana Alexandru's avatar Ioana Alexandru Committed by Android (Google) Code Review
Browse files

Merge changes I8a889842,I07d46bd9,I7e8ce558,I45ab6ad5 into main

* changes:
  Convert NotificationActivityStarter to kotlin
  Make empty shade text react to Modes changes
  Make EmptyShadeView a LaunchableView
  Migrate EmptyShadeView to recommended architecture
parents 3bd16e84 0187fa31
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -30,6 +30,16 @@ flag {
  }
}

flag {
  name: "modes_ui_empty_shade"
  namespace: "systemui"
  description: "Shows mode that is currently blocking notifications in the empty shade; dependent on flags modes_api and modes_ui"
  bug: "366003631"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}

flag {
  name: "modes_ui_test"
  namespace: "systemui"
+7 −0
Original line number Diff line number Diff line
@@ -167,6 +167,13 @@ public class TestModeBuilder {
        return this;
    }

    public TestModeBuilder setVisualEffect(int effect, boolean allowed) {
        ZenPolicy newPolicy = new ZenPolicy.Builder(mRule.getZenPolicy())
                .showVisualEffect(effect, allowed).build();
        setZenPolicy(newPolicy);
        return this;
    }

    public TestModeBuilder setEnabled(boolean enabled) {
        return setEnabled(enabled, /* byUser= */ false);
    }
+208 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.emptyshade.ui.viewmodel

import android.app.Flags
import android.app.NotificationManager.Policy
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import android.provider.Settings
import android.service.notification.ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST
import androidx.test.filters.SmallTest
import com.android.settingslib.notification.data.repository.updateNotificationPolicy
import com.android.settingslib.notification.modes.TestModeBuilder
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.policy.data.repository.zenModeRepository
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters

@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(ParameterizedAndroidJunit4::class)
@SmallTest
@EnableFlags(FooterViewRefactor.FLAG_NAME)
class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val zenModeRepository = kosmos.zenModeRepository
    private val activeNotificationListRepository = kosmos.activeNotificationListRepository

    private val underTest = kosmos.emptyShadeViewModel

    companion object {
        @JvmStatic
        @Parameters(name = "{0}")
        fun getParams(): List<FlagsParameterization> {
            return FlagsParameterization.allCombinationsOf().andSceneContainer()
        }
    }

    init {
        mSetFlagsRule.setFlagsParameterization(flags)
    }

    @Test
    fun areNotificationsHiddenInShade_true() =
        testScope.runTest {
            val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)

            zenModeRepository.updateNotificationPolicy(
                suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
            )
            zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
            runCurrent()

            assertThat(hidden).isTrue()
        }

    @Test
    fun areNotificationsHiddenInShade_false() =
        testScope.runTest {
            val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)

            zenModeRepository.updateNotificationPolicy(
                suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
            )
            zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_OFF)
            runCurrent()

            assertThat(hidden).isFalse()
        }

    @Test
    fun hasFilteredOutSeenNotifications_true() =
        testScope.runTest {
            val hasFilteredNotifs by collectLastValue(underTest.hasFilteredOutSeenNotifications)

            activeNotificationListRepository.hasFilteredOutSeenNotifications.value = true
            runCurrent()

            assertThat(hasFilteredNotifs).isTrue()
        }

    @Test
    fun hasFilteredOutSeenNotifications_false() =
        testScope.runTest {
            val hasFilteredNotifs by collectLastValue(underTest.hasFilteredOutSeenNotifications)

            activeNotificationListRepository.hasFilteredOutSeenNotifications.value = false
            runCurrent()

            assertThat(hasFilteredNotifs).isFalse()
        }

    @Test
    @EnableFlags(ModesEmptyShadeFix.FLAG_NAME)
    @DisableFlags(Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API)
    fun text_changesWhenNotifsHiddenInShade() =
        testScope.runTest {
            val text by collectLastValue(underTest.text)

            zenModeRepository.updateNotificationPolicy(
                suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
            )
            zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_OFF)
            runCurrent()

            assertThat(text).isEqualTo("No notifications")

            zenModeRepository.updateNotificationPolicy(
                suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
            )
            zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
            runCurrent()

            assertThat(text).isEqualTo("Notifications paused by Do Not Disturb")
        }

    @Test
    @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API)
    fun text_reflectsModesHidingNotifications() =
        testScope.runTest {
            val text by collectLastValue(underTest.text)

            assertThat(text).isEqualTo("No notifications")

            zenModeRepository.addMode(
                TestModeBuilder()
                    .setId("Do not disturb")
                    .setName("Do not disturb")
                    .setActive(true)
                    .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ false)
                    .build()
            )
            runCurrent()
            assertThat(text).isEqualTo("Notifications paused by Do not disturb")

            zenModeRepository.addMode(
                TestModeBuilder()
                    .setId("Work")
                    .setName("Work")
                    .setActive(true)
                    .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ false)
                    .build()
            )
            runCurrent()
            assertThat(text).isEqualTo("Notifications paused by Do not disturb and one other mode")

            zenModeRepository.addMode(
                TestModeBuilder()
                    .setId("Gym")
                    .setName("Gym")
                    .setActive(true)
                    .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ false)
                    .build()
            )
            runCurrent()
            assertThat(text).isEqualTo("Notifications paused by Do not disturb and 2 other modes")

            zenModeRepository.deactivateMode("Do not disturb")
            zenModeRepository.deactivateMode("Work")
            runCurrent()
            assertThat(text).isEqualTo("Notifications paused by Gym")
        }

    @Test
    @EnableFlags(ModesEmptyShadeFix.FLAG_NAME)
    fun footer_isVisibleWhenSeenNotifsAreFilteredOut() =
        testScope.runTest {
            val footerVisible by collectLastValue(underTest.footer.isVisible)

            activeNotificationListRepository.hasFilteredOutSeenNotifications.value = false
            runCurrent()

            assertThat(footerVisible).isFalse()

            activeNotificationListRepository.hasFilteredOutSeenNotifications.value = true
            runCurrent()

            assertThat(footerVisible).isTrue()
        }
}
+0 −55
Original line number Diff line number Diff line
@@ -18,12 +18,9 @@

package com.android.systemui.statusbar.notification.stack.ui.viewmodel

import android.app.NotificationManager.Policy
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import android.provider.Settings
import androidx.test.filters.SmallTest
import com.android.settingslib.notification.data.repository.updateNotificationPolicy
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.DisableSceneContainer
@@ -46,7 +43,6 @@ import com.android.systemui.statusbar.notification.data.repository.setActiveNoti
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
import com.android.systemui.statusbar.policy.data.repository.fakeUserSetupRepository
import com.android.systemui.statusbar.policy.data.repository.zenModeRepository
import com.android.systemui.statusbar.policy.fakeConfigurationController
import com.android.systemui.testKosmos
import com.android.systemui.util.ui.isAnimating
@@ -79,7 +75,6 @@ class NotificationListViewModelTest(flags: FlagsParameterization) : SysuiTestCas
    private val fakeRemoteInputRepository = kosmos.fakeRemoteInputRepository
    private val fakeUserSetupRepository = kosmos.fakeUserSetupRepository
    private val headsUpRepository = kosmos.headsUpNotificationRepository
    private val zenModeRepository = kosmos.zenModeRepository

    private val shadeTestUtil by lazy { kosmos.shadeTestUtil }

@@ -265,56 +260,6 @@ class NotificationListViewModelTest(flags: FlagsParameterization) : SysuiTestCas
            assertThat(shouldShow).isFalse()
        }

    @Test
    fun areNotificationsHiddenInShade_true() =
        testScope.runTest {
            val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)

            zenModeRepository.updateNotificationPolicy(
                suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
            )
            zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
            runCurrent()

            assertThat(hidden).isTrue()
        }

    @Test
    fun areNotificationsHiddenInShade_false() =
        testScope.runTest {
            val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)

            zenModeRepository.updateNotificationPolicy(
                suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
            )
            zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_OFF)
            runCurrent()

            assertThat(hidden).isFalse()
        }

    @Test
    fun hasFilteredOutSeenNotifications_true() =
        testScope.runTest {
            val hasFilteredNotifs by collectLastValue(underTest.hasFilteredOutSeenNotifications)

            activeNotificationListRepository.hasFilteredOutSeenNotifications.value = true
            runCurrent()

            assertThat(hasFilteredNotifs).isTrue()
        }

    @Test
    fun hasFilteredOutSeenNotifications_false() =
        testScope.runTest {
            val hasFilteredNotifs by collectLastValue(underTest.hasFilteredOutSeenNotifications)

            activeNotificationListRepository.hasFilteredOutSeenNotifications.value = false
            runCurrent()

            assertThat(hasFilteredNotifs).isFalse()
        }

    @Test
    fun shouldIncludeFooterView_trueWhenShade() =
        testScope.runTest {
+44 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.provider.Settings.Secure.ZEN_DURATION
import android.provider.Settings.Secure.ZEN_DURATION_FOREVER
import android.provider.Settings.Secure.ZEN_DURATION_PROMPT
import android.service.notification.SystemZenRules
import android.service.notification.ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
@@ -34,6 +35,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.shared.settings.data.repository.secureSettingsRepository
import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix
import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository
import com.android.systemui.statusbar.policy.data.repository.fakeZenModeRepository
import com.android.systemui.testKosmos
@@ -379,4 +381,46 @@ class ZenModeInteractorTest : SysuiTestCase() {

            assertThat(dndMode!!.isActive).isTrue()
        }

    @Test
    @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API)
    fun modesHidingNotifications_onlyIncludesModesWithNotifListSuppression() =
        testScope.runTest {
            val modesHidingNotifications by collectLastValue(underTest.modesHidingNotifications)

            zenModeRepository.addModes(
                listOf(
                    TestModeBuilder()
                        .setName("Not active, no list suppression")
                        .setActive(false)
                        .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ true)
                        .build(),
                    TestModeBuilder()
                        .setName("Not active, has list suppression")
                        .setActive(false)
                        .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ false)
                        .build(),
                    TestModeBuilder()
                        .setName("No list suppression")
                        .setActive(true)
                        .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ true)
                        .build(),
                    TestModeBuilder()
                        .setName("Has list suppression 1")
                        .setActive(true)
                        .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ false)
                        .build(),
                    TestModeBuilder()
                        .setName("Has list suppression 2")
                        .setActive(true)
                        .setVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, /* allowed= */ false)
                        .build(),
                )
            )
            runCurrent()

            assertThat(modesHidingNotifications?.map { it.name })
                .containsExactly("Has list suppression 1", "Has list suppression 2")
                .inOrder()
        }
}
Loading