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

Commit 50cd1567 authored by Lucas Silva's avatar Lucas Silva Committed by Android (Google) Code Review
Browse files

Merge "Create new startable to handle initializing the app widget host" into main

parents eb85dd84 694f32a4
Loading
Loading
Loading
Loading
+8 −75
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import com.android.systemui.communal.data.db.CommunalWidgetItem
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.communal.widgets.WidgetConfigurator
import com.android.systemui.communal.widgets.widgetConfiguratorFail
import com.android.systemui.communal.widgets.widgetConfiguratorSuccess
import com.android.systemui.coroutines.collectLastValue
@@ -45,8 +44,7 @@ import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -62,24 +60,17 @@ import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidJUnit4::class)
class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Mock private lateinit var appWidgetManagerOptional: Optional<AppWidgetManager>

    @Mock private lateinit var appWidgetManager: AppWidgetManager

    @Mock private lateinit var appWidgetHost: CommunalAppWidgetHost

    @Mock private lateinit var stopwatchProviderInfo: AppWidgetProviderInfo

    @Mock private lateinit var providerInfoA: AppWidgetProviderInfo

    @Mock private lateinit var communalWidgetHost: CommunalWidgetHost

    @Mock private lateinit var communalWidgetDao: CommunalWidgetDao

    private lateinit var logBuffer: LogBuffer
    private lateinit var fakeWidgets: MutableStateFlow<Map<CommunalItemRank, CommunalWidgetItem>>

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

    private val fakeAllowlist =
@@ -94,7 +85,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        fakeWidgets = MutableStateFlow(emptyMap())
        logBuffer = logcatLogBuffer(name = "CommunalWidgetRepoImplTest")

        setAppWidgetIds(emptyList())
@@ -102,13 +93,11 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
        overrideResource(R.array.config_communalWidgetAllowlist, fakeAllowlist.toTypedArray())

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

        underTest =
            CommunalWidgetRepositoryImpl(
                appWidgetManagerOptional,
                Optional.of(appWidgetManager),
                appWidgetHost,
                testScope.backgroundScope,
                kosmos.testDispatcher,
@@ -119,30 +108,16 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    }

    @Test
    fun neverQueryDbForWidgets_whenHostIsInactive() =
    fun communalWidgets_queryWidgetsFromDb() =
        testScope.runTest {
            underTest.updateAppWidgetHostActive(false)
            underTest.communalWidgets.launchIn(testScope.backgroundScope)
            runCurrent()

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

    @Test
    fun communalWidgets_whenHostIsActive_queryWidgetsFromDb() =
        testScope.runTest {
            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)))
            fakeWidgets.value = mapOf(communalItemRankEntry to communalWidgetItemEntry)
            whenever(appWidgetManager.getAppWidgetInfo(anyInt())).thenReturn(providerInfoA)

            installedProviders(listOf(stopwatchProviderInfo))

            val communalWidgets by collectLastValue(underTest.communalWidgets)
            runCurrent()
            verify(communalWidgetDao).getWidgets()
            assertThat(communalWidgets)
                .containsExactly(
@@ -157,8 +132,6 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Test
    fun addWidget_allocateId_bindWidget_andAddToDb() =
        testScope.runTest {
            underTest.updateAppWidgetHostActive(true)

            val provider = ComponentName("pkg_name", "cls_name")
            val id = 1
            val priority = 1
@@ -176,8 +149,6 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Test
    fun addWidget_configurationFails_doNotAddWidgetToDb() =
        testScope.runTest {
            underTest.updateAppWidgetHostActive(true)

            val provider = ComponentName("pkg_name", "cls_name")
            val id = 1
            val priority = 1
@@ -195,23 +166,13 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Test
    fun addWidget_configurationThrowsError_doNotAddWidgetToDb() =
        testScope.runTest {
            underTest.updateAppWidgetHostActive(true)

            val provider = ComponentName("pkg_name", "cls_name")
            val id = 1
            val priority = 1
            whenever(communalWidgetHost.getAppWidgetInfo(id))
                .thenReturn(PROVIDER_INFO_REQUIRES_CONFIGURATION)
            whenever(communalWidgetHost.allocateIdAndBindWidget(provider)).thenReturn(id)
            underTest.addWidget(
                provider,
                priority,
                object : WidgetConfigurator {
                    override suspend fun configureWidget(appWidgetId: Int): Boolean {
                        throw IllegalStateException("some error")
                    }
                }
            )
            underTest.addWidget(provider, priority) { throw IllegalStateException("some error") }
            runCurrent()

            verify(communalWidgetHost).allocateIdAndBindWidget(provider)
@@ -222,8 +183,6 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Test
    fun addWidget_configurationNotRequired_doesNotConfigure_addWidgetToDb() =
        testScope.runTest {
            underTest.updateAppWidgetHostActive(true)

            val provider = ComponentName("pkg_name", "cls_name")
            val id = 1
            val priority = 1
@@ -241,8 +200,6 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Test
    fun deleteWidget_removeWidgetId_andDeleteFromDb() =
        testScope.runTest {
            underTest.updateAppWidgetHostActive(true)

            val id = 1
            underTest.deleteWidget(id)
            runCurrent()
@@ -254,8 +211,6 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    @Test
    fun reorderWidgets_queryDb() =
        testScope.runTest {
            underTest.updateAppWidgetHostActive(true)

            val widgetIdToPriorityMap = mapOf(104 to 1, 103 to 2, 101 to 3)
            underTest.updateWidgetOrder(widgetIdToPriorityMap)
            runCurrent()
@@ -263,28 +218,6 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
            verify(communalWidgetDao).updateWidgetOrder(widgetIdToPriorityMap)
        }

    @Test
    fun appWidgetHost_startListening() =
        testScope.runTest {
            verify(appWidgetHost, never()).startListening()

            underTest.updateAppWidgetHostActive(true)

            verify(appWidgetHost).startListening()
        }

    @Test
    fun appWidgetHost_stopListening() =
        testScope.runTest {
            underTest.updateAppWidgetHostActive(true)

            verify(appWidgetHost).startListening()

            underTest.updateAppWidgetHostActive(false)

            verify(appWidgetHost).stopListening()
        }

    private fun installedProviders(providers: List<AppWidgetProviderInfo>) {
        whenever(appWidgetManager.installedProviders).thenReturn(providers)
    }
+0 −11
Original line number Diff line number Diff line
@@ -80,15 +80,4 @@ class CommunalInteractorCommunalDisabledTest : SysuiTestCase() {

            assertThat(isCommunalAvailable).isFalse()
        }

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

            keyguardRepository.setIsEncryptedOrLockdown(false)
            runCurrent()

            assertThat(widgetRepository.isHostActive()).isFalse()
        }
}
+0 −14
Original line number Diff line number Diff line
@@ -171,20 +171,6 @@ class CommunalInteractorTest : SysuiTestCase() {
            assertThat(isAvailable).isTrue()
        }

    @Test
    fun updateAppWidgetHostActive_uponStorageUnlockAsMainUser_true() =
        testScope.runTest {
            collectLastValue(underTest.isCommunalAvailable)
            assertThat(widgetRepository.isHostActive()).isFalse()

            keyguardRepository.setIsEncryptedOrLockdown(false)
            userRepository.setSelectedUserInfo(mainUser)
            keyguardRepository.setKeyguardShowing(true)
            runCurrent()

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

    @Test
    fun widget_tutorialCompletedAndWidgetsAvailable_showWidgetContent() =
        testScope.runTest {
+132 −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.widgets

import android.content.pm.UserInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
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
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class CommunalAppWidgetHostStartableTest : SysuiTestCase() {
    private val kosmos = testKosmos()

    @Mock private lateinit var appWidgetHost: CommunalAppWidgetHost

    private lateinit var underTest: CommunalAppWidgetHostStartable

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        kosmos.fakeUserRepository.setUserInfos(listOf(MAIN_USER_INFO))

        underTest =
            CommunalAppWidgetHostStartable(
                appWidgetHost,
                kosmos.communalInteractor,
                kosmos.applicationCoroutineScope,
                kosmos.testDispatcher,
            )
    }

    @Test
    fun editModeShowingStartsAppWidgetHost() =
        with(kosmos) {
            testScope.runTest {
                setCommunalAvailable(false)
                communalInteractor.setEditModeOpen(true)
                verify(appWidgetHost, never()).startListening()

                underTest.start()
                runCurrent()

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

                communalInteractor.setEditModeOpen(false)
                runCurrent()

                verify(appWidgetHost).stopListening()
            }
        }

    @Test
    fun communalShowingStartsAppWidgetHost() =
        with(kosmos) {
            testScope.runTest {
                setCommunalAvailable(true)
                communalInteractor.setEditModeOpen(false)
                verify(appWidgetHost, never()).startListening()

                underTest.start()
                runCurrent()

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

                setCommunalAvailable(false)
                runCurrent()

                verify(appWidgetHost).stopListening()
            }
        }

    @Test
    fun communalAndEditModeNotShowingNeverStartListening() =
        with(kosmos) {
            testScope.runTest {
                setCommunalAvailable(false)
                communalInteractor.setEditModeOpen(false)

                underTest.start()
                runCurrent()

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

    private suspend fun setCommunalAvailable(available: Boolean) =
        with(kosmos) {
            fakeKeyguardRepository.setIsEncryptedOrLockdown(!available)
            fakeUserRepository.setSelectedUserInfo(MAIN_USER_INFO)
            fakeKeyguardRepository.setKeyguardShowing(true)
        }

    private companion object {
        val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
    }
}
+104 −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.util.kotlin

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.android.systemui.util.kotlin.BooleanFlowOperators.and
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import com.android.systemui.util.kotlin.BooleanFlowOperators.or
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class BooleanFlowOperatorsTest : SysuiTestCase() {

    val kosmos = testKosmos()
    val testScope = kosmos.testScope

    @Test
    fun and_allTrue_returnsTrue() =
        testScope.runTest {
            val result by collectLastValue(and(TRUE, TRUE))
            assertThat(result).isTrue()
        }

    @Test
    fun and_anyFalse_returnsFalse() =
        testScope.runTest {
            val result by collectLastValue(and(TRUE, FALSE, TRUE))
            assertThat(result).isFalse()
        }

    @Test
    fun and_allFalse_returnsFalse() =
        testScope.runTest {
            val result by collectLastValue(and(FALSE, FALSE, FALSE))
            assertThat(result).isFalse()
        }

    @Test
    fun or_allTrue_returnsTrue() =
        testScope.runTest {
            val result by collectLastValue(or(TRUE, TRUE))
            assertThat(result).isTrue()
        }

    @Test
    fun or_anyTrue_returnsTrue() =
        testScope.runTest {
            val result by collectLastValue(or(FALSE, TRUE, FALSE))
            assertThat(result).isTrue()
        }

    @Test
    fun or_allFalse_returnsFalse() =
        testScope.runTest {
            val result by collectLastValue(or(FALSE, FALSE, FALSE))
            assertThat(result).isFalse()
        }

    @Test
    fun not_true_returnsFalse() =
        testScope.runTest {
            val result by collectLastValue(not(TRUE))
            assertThat(result).isFalse()
        }

    @Test
    fun not_false_returnsFalse() =
        testScope.runTest {
            val result by collectLastValue(not(FALSE))
            assertThat(result).isTrue()
        }

    private companion object {
        val TRUE: Flow<Boolean>
            get() = flowOf(true)
        val FALSE: Flow<Boolean>
            get() = flowOf(false)
    }
}
Loading