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

Commit f3b40f71 authored by Darrell Shi's avatar Darrell Shi Committed by Android (Google) Code Review
Browse files

Merge changes I3d2c6670,Iabd1f967 into main

* changes:
  Hide communal hub before strong auth granted
  Kosmos for communal interactor and widget repo tests
parents cc7796b4 17cbe981
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -67,8 +67,9 @@ fun CommunalContainer(
    // Don't show hub mode UI if keyguard is not present. This is important since we're in the
    // shade, which can be opened from many locations.
    val isKeyguardShowing by viewModel.isKeyguardVisible.collectAsState(initial = false)
    val isCommunalAvailable by viewModel.isCommunalAvailable.collectAsState()

    if (!isKeyguardShowing) {
    if (!isKeyguardShowing || !isCommunalAvailable) {
        return
    }

+45 −146
Original line number Diff line number Diff line
@@ -19,10 +19,6 @@ package com.android.systemui.communal.data.repository
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProviderInfo
import android.content.ComponentName
import android.content.Intent
import android.content.Intent.ACTION_USER_UNLOCKED
import android.os.UserHandle
import android.os.UserManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -33,10 +29,12 @@ import com.android.systemui.communal.shared.CommunalWidgetHost
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
import com.android.systemui.communal.widgets.CommunalAppWidgetHost
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.FakeLogBuffer
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -44,8 +42,6 @@ import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -67,12 +63,6 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {

    @Mock private lateinit var appWidgetHost: CommunalAppWidgetHost

    @Mock private lateinit var userManager: UserManager

    @Mock private lateinit var userHandle: UserHandle

    @Mock private lateinit var userTracker: UserTracker

    @Mock private lateinit var stopwatchProviderInfo: AppWidgetProviderInfo

    @Mock private lateinit var providerInfoA: AppWidgetProviderInfo
@@ -81,13 +71,11 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {

    @Mock private lateinit var communalWidgetDao: CommunalWidgetDao

    private lateinit var communalRepository: FakeCommunalRepository

    private lateinit var logBuffer: LogBuffer
    private val kosmos = testKosmos()

    private val testDispatcher = StandardTestDispatcher()
    private val testScope = kosmos.testScope

    private val testScope = TestScope(testDispatcher)
    private lateinit var logBuffer: LogBuffer

    private val fakeAllowlist =
        listOf(
@@ -96,68 +84,60 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
            "com.android.fake/WidgetProviderC",
        )

    private lateinit var underTest: CommunalWidgetRepositoryImpl

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        logBuffer = FakeLogBuffer.Factory.create()
        communalRepository = FakeCommunalRepository()
        logBuffer = logcatLogBuffer(name = "CommunalWidgetRepoImplTest")

        communalEnabled(true)
        setAppWidgetIds(emptyList())

        overrideResource(R.array.config_communalWidgetAllowlist, fakeAllowlist.toTypedArray())

        whenever(stopwatchProviderInfo.loadLabel(any())).thenReturn("Stopwatch")
        whenever(userTracker.userHandle).thenReturn(userHandle)
        whenever(communalWidgetDao.getWidgets()).thenReturn(flowOf(emptyMap()))
        whenever(appWidgetManagerOptional.isPresent).thenReturn(true)
        whenever(appWidgetManagerOptional.get()).thenReturn(appWidgetManager)
    }

    @Test
    fun neverQueryDbForWidgets_whenFeatureIsDisabled() =
        testScope.runTest {
            communalEnabled(false)
            val repository = initCommunalWidgetRepository()
            repository.communalWidgets.launchIn(backgroundScope)
            runCurrent()

            verify(communalWidgetDao, never()).getWidgets()
        underTest =
            CommunalWidgetRepositoryImpl(
                appWidgetManagerOptional,
                appWidgetHost,
                testScope.backgroundScope,
                kosmos.testDispatcher,
                communalWidgetHost,
                communalWidgetDao,
                logBuffer,
            )
    }

    @Test
    fun neverQueryDbForWidgets_whenFeatureEnabled_andUserLocked() =
    fun neverQueryDbForWidgets_whenHostIsInactive() =
        testScope.runTest {
            userUnlocked(false)
            val repository = initCommunalWidgetRepository()
            repository.communalWidgets.launchIn(backgroundScope)
            underTest.updateAppWidgetHostActive(false)
            underTest.communalWidgets.launchIn(testScope.backgroundScope)
            runCurrent()

            verify(communalWidgetDao, never()).getWidgets()
        }

    @Test
    fun communalWidgets_whenUserUnlocked_queryWidgetsFromDb() =
    fun communalWidgets_whenHostIsActive_queryWidgetsFromDb() =
        testScope.runTest {
            userUnlocked(false)
            val repository = initCommunalWidgetRepository()
            val communalWidgets by collectLastValue(repository.communalWidgets)
            runCurrent()
            underTest.updateAppWidgetHostActive(true)

            val communalItemRankEntry = CommunalItemRank(uid = 1L, rank = 1)
            val communalWidgetItemEntry = CommunalWidgetItem(uid = 1L, 1, "pk_name/cls_name", 1L)
            whenever(communalWidgetDao.getWidgets())
                .thenReturn(flowOf(mapOf(communalItemRankEntry to communalWidgetItemEntry)))
            whenever(appWidgetManager.getAppWidgetInfo(anyInt())).thenReturn(providerInfoA)

            userUnlocked(true)
            installedProviders(listOf(stopwatchProviderInfo))
            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
                context,
                Intent(ACTION_USER_UNLOCKED)
            )
            runCurrent()

            val communalWidgets by collectLastValue(underTest.communalWidgets)
            runCurrent()
            verify(communalWidgetDao).getWidgets()
            assertThat(communalWidgets)
                .containsExactly(
@@ -172,9 +152,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Test
    fun addWidget_allocateId_bindWidget_andAddToDb() =
        testScope.runTest {
            userUnlocked(true)
            val repository = initCommunalWidgetRepository()
            runCurrent()
            underTest.updateAppWidgetHostActive(true)

            val provider = ComponentName("pkg_name", "cls_name")
            val id = 1
@@ -182,7 +160,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
            whenever(communalWidgetHost.requiresConfiguration(id)).thenReturn(true)
            whenever(communalWidgetHost.allocateIdAndBindWidget(any<ComponentName>()))
                .thenReturn(id)
            repository.addWidget(provider, priority) { true }
            underTest.addWidget(provider, priority) { true }
            runCurrent()

            verify(communalWidgetHost).allocateIdAndBindWidget(provider)
@@ -192,16 +170,14 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Test
    fun addWidget_configurationFails_doNotAddWidgetToDb() =
        testScope.runTest {
            userUnlocked(true)
            val repository = initCommunalWidgetRepository()
            runCurrent()
            underTest.updateAppWidgetHostActive(true)

            val provider = ComponentName("pkg_name", "cls_name")
            val id = 1
            val priority = 1
            whenever(communalWidgetHost.requiresConfiguration(id)).thenReturn(true)
            whenever(communalWidgetHost.allocateIdAndBindWidget(provider)).thenReturn(id)
            repository.addWidget(provider, priority) { false }
            underTest.addWidget(provider, priority) { false }
            runCurrent()

            verify(communalWidgetHost).allocateIdAndBindWidget(provider)
@@ -212,16 +188,14 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Test
    fun addWidget_configurationThrowsError_doNotAddWidgetToDb() =
        testScope.runTest {
            userUnlocked(true)
            val repository = initCommunalWidgetRepository()
            runCurrent()
            underTest.updateAppWidgetHostActive(true)

            val provider = ComponentName("pkg_name", "cls_name")
            val id = 1
            val priority = 1
            whenever(communalWidgetHost.requiresConfiguration(id)).thenReturn(true)
            whenever(communalWidgetHost.allocateIdAndBindWidget(provider)).thenReturn(id)
            repository.addWidget(provider, priority) { throw IllegalStateException("some error") }
            underTest.addWidget(provider, priority) { throw IllegalStateException("some error") }
            runCurrent()

            verify(communalWidgetHost).allocateIdAndBindWidget(provider)
@@ -232,9 +206,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Test
    fun addWidget_configurationNotRequired_doesNotConfigure_addWidgetToDb() =
        testScope.runTest {
            userUnlocked(true)
            val repository = initCommunalWidgetRepository()
            runCurrent()
            underTest.updateAppWidgetHostActive(true)

            val provider = ComponentName("pkg_name", "cls_name")
            val id = 1
@@ -243,7 +215,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
            whenever(communalWidgetHost.allocateIdAndBindWidget(any<ComponentName>()))
                .thenReturn(id)
            var configured = false
            repository.addWidget(provider, priority) {
            underTest.addWidget(provider, priority) {
                configured = true
                true
            }
@@ -257,12 +229,10 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Test
    fun deleteWidget_removeWidgetId_andDeleteFromDb() =
        testScope.runTest {
            userUnlocked(true)
            val repository = initCommunalWidgetRepository()
            runCurrent()
            underTest.updateAppWidgetHostActive(true)

            val id = 1
            repository.deleteWidget(id)
            underTest.deleteWidget(id)
            runCurrent()

            verify(communalWidgetDao).deleteWidgetById(id)
@@ -272,108 +242,37 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Test
    fun reorderWidgets_queryDb() =
        testScope.runTest {
            userUnlocked(true)
            val repository = initCommunalWidgetRepository()
            runCurrent()
            underTest.updateAppWidgetHostActive(true)

            val widgetIdToPriorityMap = mapOf(104 to 1, 103 to 2, 101 to 3)
            repository.updateWidgetOrder(widgetIdToPriorityMap)
            underTest.updateWidgetOrder(widgetIdToPriorityMap)
            runCurrent()

            verify(communalWidgetDao).updateWidgetOrder(widgetIdToPriorityMap)
        }

    @Test
    fun broadcastReceiver_communalDisabled_doNotRegisterUserUnlockedBroadcastReceiver() =
    fun appWidgetHost_startListening() =
        testScope.runTest {
            communalEnabled(false)
            val repository = initCommunalWidgetRepository()
            repository.communalWidgets.launchIn(backgroundScope)
            runCurrent()
            assertThat(fakeBroadcastDispatcher.numReceiversRegistered).isEqualTo(0)
        }

    @Test
    fun broadcastReceiver_featureEnabledAndUserLocked_registerBroadcastReceiver() =
        testScope.runTest {
            userUnlocked(false)
            val repository = initCommunalWidgetRepository()
            repository.communalWidgets.launchIn(backgroundScope)
            runCurrent()
            assertThat(fakeBroadcastDispatcher.numReceiversRegistered).isEqualTo(1)
        }

    @Test
    fun appWidgetHost_userUnlocked_startListening() =
        testScope.runTest {
            userUnlocked(false)
            val repository = initCommunalWidgetRepository()
            repository.communalWidgets.launchIn(backgroundScope)
            runCurrent()
            verify(appWidgetHost, never()).startListening()

            userUnlocked(true)
            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
                context,
                Intent(ACTION_USER_UNLOCKED)
            )
            runCurrent()
            underTest.updateAppWidgetHostActive(true)

            verify(appWidgetHost).startListening()
        }

    @Test
    fun appWidgetHost_userLockedAgain_stopListening() =
    fun appWidgetHost_stopListening() =
        testScope.runTest {
            userUnlocked(false)
            val repository = initCommunalWidgetRepository()
            repository.communalWidgets.launchIn(backgroundScope)
            runCurrent()

            userUnlocked(true)
            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
                context,
                Intent(ACTION_USER_UNLOCKED)
            )
            runCurrent()
            underTest.updateAppWidgetHostActive(true)

            verify(appWidgetHost).startListening()
            verify(appWidgetHost, never()).stopListening()

            userUnlocked(false)
            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
                context,
                Intent(ACTION_USER_UNLOCKED)
            )
            runCurrent()
            underTest.updateAppWidgetHostActive(false)

            verify(appWidgetHost).stopListening()
        }

    private fun initCommunalWidgetRepository(): CommunalWidgetRepositoryImpl {
        return CommunalWidgetRepositoryImpl(
            appWidgetManagerOptional,
            appWidgetHost,
            testScope.backgroundScope,
            testDispatcher,
            fakeBroadcastDispatcher,
            communalRepository,
            communalWidgetHost,
            communalWidgetDao,
            userManager,
            userTracker,
            logBuffer,
        )
    }

    private fun communalEnabled(enabled: Boolean) {
        communalRepository.setIsCommunalEnabled(enabled)
    }

    private fun userUnlocked(userUnlocked: Boolean) {
        whenever(userManager.isUserUnlockingOrUnlocked(userHandle)).thenReturn(userUnlocked)
    }

    private fun installedProviders(providers: List<AppWidgetProviderInfo>) {
        whenever(appWidgetManager.installedProviders).thenReturn(providers)
    }
+95 −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.communal.domain.interactor

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.data.repository.FakeCommunalRepository
import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
import com.android.systemui.communal.data.repository.fakeCommunalRepository
import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.communalInteractor
import com.android.systemui.kosmos.testScope
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.Before
import org.junit.Test
import org.junit.runner.RunWith

/**
 * This class is a variation of the [CommunalInteractorTest] for cases where communal is disabled.
 */
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class CommunalInteractorCommunalDisabledTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope

    private lateinit var communalRepository: FakeCommunalRepository
    private lateinit var widgetRepository: FakeCommunalWidgetRepository
    private lateinit var keyguardRepository: FakeKeyguardRepository

    private lateinit var underTest: CommunalInteractor

    @Before
    fun setUp() {
        communalRepository = kosmos.fakeCommunalRepository
        widgetRepository = kosmos.fakeCommunalWidgetRepository
        keyguardRepository = kosmos.fakeKeyguardRepository

        communalRepository.setIsCommunalEnabled(false)

        underTest = kosmos.communalInteractor
    }

    @Test
    fun isCommunalEnabled_false() =
        testScope.runTest { assertThat(underTest.isCommunalEnabled).isFalse() }

    @Test
    fun isCommunalAvailable_whenStorageUnlock_false() =
        testScope.runTest {
            val isCommunalAvailable by collectLastValue(underTest.isCommunalAvailable)

            assertThat(isCommunalAvailable).isFalse()

            keyguardRepository.setIsEncryptedOrLockdown(false)
            runCurrent()

            assertThat(isCommunalAvailable).isFalse()
        }

    @Test
    fun updateAppWidgetHostActive_whenStorageUnlock_false() =
        testScope.runTest {
            assertThat(widgetRepository.isHostActive()).isFalse()

            keyguardRepository.setIsEncryptedOrLockdown(false)
            runCurrent()

            assertThat(widgetRepository.isHostActive()).isFalse()
        }
}
+56 −23
Original line number Diff line number Diff line
@@ -28,6 +28,11 @@ import com.android.systemui.communal.data.repository.FakeCommunalPrefsRepository
import com.android.systemui.communal.data.repository.FakeCommunalRepository
import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.fakeCommunalPrefsRepository
import com.android.systemui.communal.data.repository.fakeCommunalRepository
import com.android.systemui.communal.data.repository.fakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalSceneKey
@@ -36,15 +41,19 @@ import com.android.systemui.communal.shared.model.ObservableCommunalTransitionSt
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.communalInteractor
import com.android.systemui.keyguard.domain.interactor.editWidgetsActivityStarter
import com.android.systemui.kosmos.testScope
import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
import com.android.systemui.smartspace.data.repository.fakeSmartspaceRepository
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -52,13 +61,17 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

/**
 * This class of test cases assume that communal is enabled. For disabled cases, see
 * [CommunalInteractorCommunalDisabledTest].
 */
@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class CommunalInteractorTest : SysuiTestCase() {
    private lateinit var testScope: TestScope
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope

    private lateinit var tutorialRepository: FakeCommunalTutorialRepository
    private lateinit var communalRepository: FakeCommunalRepository
@@ -73,36 +86,56 @@ class CommunalInteractorTest : SysuiTestCase() {

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        tutorialRepository = kosmos.fakeCommunalTutorialRepository
        communalRepository = kosmos.fakeCommunalRepository
        mediaRepository = kosmos.fakeCommunalMediaRepository
        widgetRepository = kosmos.fakeCommunalWidgetRepository
        smartspaceRepository = kosmos.fakeSmartspaceRepository
        keyguardRepository = kosmos.fakeKeyguardRepository
        editWidgetsActivityStarter = kosmos.editWidgetsActivityStarter
        communalPrefsRepository = kosmos.fakeCommunalPrefsRepository

        underTest = kosmos.communalInteractor
    }

        testScope = TestScope(StandardTestDispatcher())
    @Test
    fun communalEnabled_true() =
        testScope.runTest { assertThat(underTest.isCommunalEnabled).isTrue() }

        val withDeps = CommunalInteractorFactory.create(testScope)
    @Test
    fun isCommunalAvailable_trueWhenStorageUnlock() =
        testScope.runTest {
            val isAvailable by collectLastValue(underTest.isCommunalAvailable)
            assertThat(isAvailable).isFalse()

        tutorialRepository = withDeps.tutorialRepository
        communalRepository = withDeps.communalRepository
        mediaRepository = withDeps.mediaRepository
        widgetRepository = withDeps.widgetRepository
        smartspaceRepository = withDeps.smartspaceRepository
        keyguardRepository = withDeps.keyguardRepository
        editWidgetsActivityStarter = withDeps.editWidgetsActivityStarter
        communalPrefsRepository = withDeps.communalPrefsRepository
            keyguardRepository.setIsEncryptedOrLockdown(false)
            runCurrent()

        underTest = withDeps.communalInteractor
            assertThat(isAvailable).isTrue()
        }

    @Test
    fun communalEnabled() =
    fun isCommunalAvailable_whenStorageUnlock_true() =
        testScope.runTest {
            communalRepository.setIsCommunalEnabled(true)
            assertThat(underTest.isCommunalEnabled).isTrue()
            val isAvailable by collectLastValue(underTest.isCommunalAvailable)
            assertThat(isAvailable).isFalse()

            keyguardRepository.setIsEncryptedOrLockdown(false)
            runCurrent()

            assertThat(isAvailable).isTrue()
        }

    @Test
    fun communalDisabled() =
    fun updateAppWidgetHostActive_uponStorageUnlock_true() =
        testScope.runTest {
            communalRepository.setIsCommunalEnabled(false)
            assertThat(underTest.isCommunalEnabled).isFalse()
            collectLastValue(underTest.isCommunalAvailable)
            assertThat(widgetRepository.isHostActive()).isFalse()

            keyguardRepository.setIsEncryptedOrLockdown(false)
            runCurrent()

            assertThat(widgetRepository.isHostActive()).isTrue()
        }

    @Test
+27 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading