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

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

Merge "Start widget configuration activity if needed" into main

parents b5c9babe e897920b
Loading
Loading
Loading
Loading
+106 −94
Original line number Diff line number Diff line
@@ -19,14 +19,14 @@ package com.android.systemui.communal.data.repository
import android.appwidget.AppWidgetHost
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProviderInfo
import android.content.BroadcastReceiver
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
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.communal.data.db.CommunalItemRank
import com.android.systemui.communal.data.db.CommunalWidgetDao
import com.android.systemui.communal.data.db.CommunalWidgetItem
@@ -38,15 +38,12 @@ import com.android.systemui.log.core.FakeLogBuffer
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.kotlinArgumentCaptor
import com.android.systemui.util.mockito.nullable
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.collect
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -55,8 +52,8 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

@@ -70,8 +67,6 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {

    @Mock private lateinit var appWidgetHost: AppWidgetHost

    @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher

    @Mock private lateinit var userManager: UserManager

    @Mock private lateinit var userHandle: UserHandle
@@ -125,10 +120,10 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
        testScope.runTest {
            communalEnabled(false)
            val repository = initCommunalWidgetRepository()
            collectLastValue(repository.communalWidgets)()
            repository.communalWidgets.launchIn(backgroundScope)
            runCurrent()

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

    @Test
@@ -136,10 +131,10 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
        testScope.runTest {
            userUnlocked(false)
            val repository = initCommunalWidgetRepository()
            collectLastValue(repository.communalWidgets)()
            repository.communalWidgets.launchIn(backgroundScope)
            runCurrent()

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

    @Test
@@ -147,8 +142,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
        testScope.runTest {
            userUnlocked(false)
            val repository = initCommunalWidgetRepository()
            val communalWidgets = collectLastValue(repository.communalWidgets)
            communalWidgets()
            val communalWidgets by collectLastValue(repository.communalWidgets)
            runCurrent()
            val communalItemRankEntry = CommunalItemRank(uid = 1L, rank = 1)
            val communalWidgetItemEntry = CommunalWidgetItem(uid = 1L, 1, "pk_name/cls_name", 1L)
@@ -158,11 +152,14 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {

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

            verify(communalWidgetDao).getWidgets()
            assertThat(communalWidgets())
            assertThat(communalWidgets)
                .containsExactly(
                    CommunalWidgetContentModel(
                        appWidgetId = communalWidgetItemEntry.widgetId,
@@ -182,9 +179,10 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
            val provider = ComponentName("pkg_name", "cls_name")
            val id = 1
            val priority = 1
            whenever(communalWidgetHost.requiresConfiguration(id)).thenReturn(true)
            whenever(communalWidgetHost.allocateIdAndBindWidget(any<ComponentName>()))
                .thenReturn(id)
            repository.addWidget(provider, priority)
            repository.addWidget(provider, priority) { true }
            runCurrent()

            verify(communalWidgetHost).allocateIdAndBindWidget(provider)
@@ -192,75 +190,117 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
        }

    @Test
    fun deleteWidget_removeWidgetId_andDeleteFromDb() =
    fun addWidget_configurationFails_doNotAddWidgetToDb() =
        testScope.runTest {
            userUnlocked(true)
            val repository = initCommunalWidgetRepository()
            runCurrent()

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

            verify(communalWidgetDao).deleteWidgetById(id)
            verify(communalWidgetHost).allocateIdAndBindWidget(provider)
            verify(communalWidgetDao, never()).addWidget(id, provider, priority)
            verify(appWidgetHost).deleteAppWidgetId(id)
        }

    @Test
    fun reorderWidgets_queryDb() =
    fun addWidget_configurationThrowsError_doNotAddWidgetToDb() =
        testScope.runTest {
            userUnlocked(true)
            val repository = initCommunalWidgetRepository()
            runCurrent()

            val widgetIdToPriorityMap = mapOf(104 to 1, 103 to 2, 101 to 3)
            repository.updateWidgetOrder(widgetIdToPriorityMap)
            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") }
            runCurrent()

            verify(communalWidgetDao).updateWidgetOrder(widgetIdToPriorityMap)
            verify(communalWidgetHost).allocateIdAndBindWidget(provider)
            verify(communalWidgetDao, never()).addWidget(id, provider, priority)
            verify(appWidgetHost).deleteAppWidgetId(id)
        }

    @Test
    fun broadcastReceiver_communalDisabled_doNotRegisterUserUnlockedBroadcastReceiver() =
    fun addWidget_configurationNotRequired_doesNotConfigure_addWidgetToDb() =
        testScope.runTest {
            communalEnabled(false)
            userUnlocked(true)
            val repository = initCommunalWidgetRepository()
            collectLastValue(repository.communalWidgets)()
            verifyBroadcastReceiverNeverRegistered()
            runCurrent()

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

            verify(communalWidgetHost).allocateIdAndBindWidget(provider)
            verify(communalWidgetDao).addWidget(id, provider, priority)
            assertThat(configured).isFalse()
        }

    @Test
    fun broadcastReceiver_featureEnabledAndUserUnlocked_doNotRegisterBroadcastReceiver() =
    fun deleteWidget_removeWidgetId_andDeleteFromDb() =
        testScope.runTest {
            userUnlocked(true)
            val repository = initCommunalWidgetRepository()
            collectLastValue(repository.communalWidgets)()
            verifyBroadcastReceiverNeverRegistered()
            runCurrent()

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

            verify(communalWidgetDao).deleteWidgetById(id)
            verify(appWidgetHost).deleteAppWidgetId(id)
        }

    @Test
    fun broadcastReceiver_featureEnabledAndUserLocked_registerBroadcastReceiver() =
    fun reorderWidgets_queryDb() =
        testScope.runTest {
            userUnlocked(false)
            userUnlocked(true)
            val repository = initCommunalWidgetRepository()
            collectLastValue(repository.communalWidgets)()
            verifyBroadcastReceiverRegistered()
            runCurrent()

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

            verify(communalWidgetDao).updateWidgetOrder(widgetIdToPriorityMap)
        }

    @Test
    fun broadcastReceiver_whenFlowFinishes_unregisterBroadcastReceiver() =
    fun broadcastReceiver_communalDisabled_doNotRegisterUserUnlockedBroadcastReceiver() =
        testScope.runTest {
            userUnlocked(false)
            communalEnabled(false)
            val repository = initCommunalWidgetRepository()

            val job = launch { repository.communalWidgets.collect() }
            repository.communalWidgets.launchIn(backgroundScope)
            runCurrent()
            val receiver = broadcastReceiverUpdate()
            assertThat(fakeBroadcastDispatcher.numReceiversRegistered).isEqualTo(0)
        }

            job.cancel()
    @Test
    fun broadcastReceiver_featureEnabledAndUserLocked_registerBroadcastReceiver() =
        testScope.runTest {
            userUnlocked(false)
            val repository = initCommunalWidgetRepository()
            repository.communalWidgets.launchIn(backgroundScope)
            runCurrent()

            verify(broadcastDispatcher).unregisterReceiver(receiver)
            assertThat(fakeBroadcastDispatcher.numReceiversRegistered).isEqualTo(1)
        }

    @Test
@@ -268,12 +308,16 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
        testScope.runTest {
            userUnlocked(false)
            val repository = initCommunalWidgetRepository()
            collectLastValue(repository.communalWidgets)()
            verify(appWidgetHost, Mockito.never()).startListening()
            repository.communalWidgets.launchIn(backgroundScope)
            runCurrent()
            verify(appWidgetHost, never()).startListening()

            userUnlocked(true)
            broadcastReceiverUpdate()
            collectLastValue(repository.communalWidgets)()
            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
                context,
                Intent(ACTION_USER_UNLOCKED)
            )
            runCurrent()

            verify(appWidgetHost).startListening()
        }
@@ -283,18 +327,25 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
        testScope.runTest {
            userUnlocked(false)
            val repository = initCommunalWidgetRepository()
            collectLastValue(repository.communalWidgets)()
            repository.communalWidgets.launchIn(backgroundScope)
            runCurrent()

            userUnlocked(true)
            broadcastReceiverUpdate()
            collectLastValue(repository.communalWidgets)()
            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
                context,
                Intent(ACTION_USER_UNLOCKED)
            )
            runCurrent()

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

            userUnlocked(false)
            broadcastReceiverUpdate()
            collectLastValue(repository.communalWidgets)()
            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
                context,
                Intent(ACTION_USER_UNLOCKED)
            )
            runCurrent()

            verify(appWidgetHost).stopListening()
        }
@@ -305,7 +356,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
            appWidgetHost,
            testScope.backgroundScope,
            testDispatcher,
            broadcastDispatcher,
            fakeBroadcastDispatcher,
            communalRepository,
            communalWidgetHost,
            communalWidgetDao,
@@ -315,45 +366,6 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
        )
    }

    private fun verifyBroadcastReceiverRegistered() {
        verify(broadcastDispatcher)
            .registerReceiver(
                any(),
                any(),
                nullable(),
                nullable(),
                anyInt(),
                nullable(),
            )
    }

    private fun verifyBroadcastReceiverNeverRegistered() {
        verify(broadcastDispatcher, Mockito.never())
            .registerReceiver(
                any(),
                any(),
                nullable(),
                nullable(),
                anyInt(),
                nullable(),
            )
    }

    private fun broadcastReceiverUpdate(): BroadcastReceiver {
        val broadcastReceiverCaptor = kotlinArgumentCaptor<BroadcastReceiver>()
        verify(broadcastDispatcher)
            .registerReceiver(
                broadcastReceiverCaptor.capture(),
                any(),
                nullable(),
                nullable(),
                anyInt(),
                nullable(),
            )
        broadcastReceiverCaptor.value.onReceive(null, null)
        return broadcastReceiverCaptor.value
    }

    private fun communalEnabled(enabled: Boolean) {
        communalRepository.setIsCommunalEnabled(enabled)
    }
+59 −1
Original line number Diff line number Diff line
@@ -16,7 +16,11 @@

package com.android.systemui.communal.view.viewmodel

import android.app.Activity.RESULT_CANCELED
import android.app.Activity.RESULT_OK
import android.app.smartspace.SmartspaceTarget
import android.appwidget.AppWidgetHost
import android.content.ComponentName
import android.os.PowerManager
import android.provider.Settings
import android.widget.RemoteViews
@@ -42,6 +46,8 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import javax.inject.Provider
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -50,12 +56,14 @@ import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class CommunalEditModeViewModelTest : SysuiTestCase() {
    @Mock private lateinit var mediaHost: MediaHost
    @Mock private lateinit var shadeViewController: ShadeViewController
    @Mock private lateinit var powerManager: PowerManager
    @Mock private lateinit var appWidgetHost: AppWidgetHost

    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
@@ -73,7 +81,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        val withDeps = CommunalInteractorFactory.create()
        val withDeps = CommunalInteractorFactory.create(testScope)
        keyguardRepository = withDeps.keyguardRepository
        communalRepository = withDeps.communalRepository
        tutorialRepository = withDeps.tutorialRepository
@@ -84,6 +92,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
        underTest =
            CommunalEditModeViewModel(
                withDeps.communalInteractor,
                appWidgetHost,
                Provider { shadeViewController },
                powerManager,
                mediaHost,
@@ -145,4 +154,53 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
            )
            .isEqualTo(false)
    }

    @Test
    fun addingWidgetTriggersConfiguration() =
        testScope.runTest {
            val provider = ComponentName("pkg.test", "testWidget")
            val widgetToConfigure by collectLastValue(underTest.widgetsToConfigure)
            assertThat(widgetToConfigure).isNull()
            underTest.onAddWidget(componentName = provider, priority = 0)
            assertThat(widgetToConfigure).isEqualTo(1)
        }

    @Test
    fun settingResultOkAddsWidget() =
        testScope.runTest {
            val provider = ComponentName("pkg.test", "testWidget")
            val widgetAdded by collectLastValue(widgetRepository.widgetAdded)
            assertThat(widgetAdded).isNull()
            underTest.onAddWidget(componentName = provider, priority = 0)
            assertThat(widgetAdded).isNull()
            underTest.setConfigurationResult(RESULT_OK)
            assertThat(widgetAdded).isEqualTo(1)
        }

    @Test
    fun settingResultCancelledDoesNotAddWidget() =
        testScope.runTest {
            val provider = ComponentName("pkg.test", "testWidget")
            val widgetAdded by collectLastValue(widgetRepository.widgetAdded)
            assertThat(widgetAdded).isNull()
            underTest.onAddWidget(componentName = provider, priority = 0)
            assertThat(widgetAdded).isNull()
            underTest.setConfigurationResult(RESULT_CANCELED)
            assertThat(widgetAdded).isNull()
        }

    @Test(expected = IllegalStateException::class)
    fun settingResultBeforeWidgetAddedThrowsException() {
        underTest.setConfigurationResult(RESULT_OK)
    }

    @Test(expected = IllegalStateException::class)
    fun addingWidgetWhileConfigurationActiveFails() =
        testScope.runTest {
            val providerOne = ComponentName("pkg.test", "testWidget")
            underTest.onAddWidget(componentName = providerOne, priority = 0)
            runCurrent()
            val providerTwo = ComponentName("pkg.test", "testWidget2")
            underTest.onAddWidget(componentName = providerTwo, priority = 0)
        }
}
+69 −43
Original line number Diff line number Diff line
@@ -18,14 +18,12 @@ package com.android.systemui.communal.data.repository

import android.appwidget.AppWidgetHost
import android.appwidget.AppWidgetManager
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.UserManager
import androidx.annotation.WorkerThread
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.communal.data.db.CommunalItemRank
import com.android.systemui.communal.data.db.CommunalWidgetDao
import com.android.systemui.communal.data.db.CommunalWidgetItem
@@ -40,17 +38,21 @@ import com.android.systemui.log.dagger.CommunalLog
import com.android.systemui.settings.UserTracker
import java.util.Optional
import javax.inject.Inject
import kotlin.coroutines.cancellation.CancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/** Encapsulates the state of widgets for communal mode. */
interface CommunalWidgetRepository {
@@ -58,7 +60,11 @@ interface CommunalWidgetRepository {
    val communalWidgets: Flow<List<CommunalWidgetContentModel>>

    /** Add a widget at the specified position in the app widget service and the database. */
    fun addWidget(provider: ComponentName, priority: Int) {}
    fun addWidget(
        provider: ComponentName,
        priority: Int,
        configureWidget: suspend (id: Int) -> Boolean
    ) {}

    /** Delete a widget by id from app widget service and the database. */
    fun deleteWidget(widgetId: Int) {}
@@ -97,37 +103,22 @@ constructor(
    // Whether the [AppWidgetHost] is listening for updates.
    private var isHostListening = false

    private val isUserUnlocked: Flow<Boolean> =
        callbackFlow {
                if (!communalRepository.isCommunalEnabled) {
                    awaitClose()
                }

                fun isUserUnlockingOrUnlocked(): Boolean {
                    return userManager.isUserUnlockingOrUnlocked(userTracker.userHandle)
                }

                fun send() {
                    trySendWithFailureLogging(isUserUnlockingOrUnlocked(), TAG)
                }
    private suspend fun isUserUnlockingOrUnlocked(): Boolean =
        withContext(bgDispatcher) { userManager.isUserUnlockingOrUnlocked(userTracker.userHandle) }

                if (isUserUnlockingOrUnlocked()) {
                    send()
                    awaitClose()
                } else {
                    val receiver =
                        object : BroadcastReceiver() {
                            override fun onReceive(context: Context?, intent: Intent?) {
                                send()
                            }
                        }

                    broadcastDispatcher.registerReceiver(
                        receiver,
                        IntentFilter(Intent.ACTION_USER_UNLOCKED),
    private val isUserUnlocked: Flow<Boolean> =
        flowOf(communalRepository.isCommunalEnabled)
            .flatMapLatest { enabled ->
                if (enabled) {
                    broadcastDispatcher
                        .broadcastFlow(
                            filter = IntentFilter(Intent.ACTION_USER_UNLOCKED),
                            user = userTracker.userHandle
                        )

                    awaitClose { broadcastDispatcher.unregisterReceiver(receiver) }
                        .onStart { emit(Unit) }
                        .mapLatest { isUserUnlockingOrUnlocked() }
                } else {
                    emptyFlow()
                }
            }
            .distinctUntilChanged()
@@ -148,18 +139,52 @@ constructor(
            if (!isHostActive || !appWidgetManager.isPresent) {
                return@flatMapLatest flowOf(emptyList())
            }
            communalWidgetDao.getWidgets().map { it.map(::mapToContentModel) }
            communalWidgetDao
                .getWidgets()
                .map { it.map(::mapToContentModel) }
                // As this reads from a database and triggers IPCs to AppWidgetManager,
                // it should be executed in the background.
                .flowOn(bgDispatcher)
        }

    override fun addWidget(provider: ComponentName, priority: Int) {
    override fun addWidget(
        provider: ComponentName,
        priority: Int,
        configureWidget: suspend (id: Int) -> Boolean
    ) {
        applicationScope.launch(bgDispatcher) {
            val id = communalWidgetHost.allocateIdAndBindWidget(provider)
            id?.let {
            if (id != null) {
                val configured =
                    if (communalWidgetHost.requiresConfiguration(id)) {
                        logger.i("Widget ${provider.flattenToString()} requires configuration.")
                        try {
                            configureWidget.invoke(id)
                        } catch (ex: Exception) {
                            // Cleanup the app widget id if an error happens during configuration.
                            logger.e("Error during widget configuration, cleaning up id $id", ex)
                            if (ex is CancellationException) {
                                appWidgetHost.deleteAppWidgetId(id)
                                // Re-throw cancellation to ensure the parent coroutine also gets
                                // cancelled.
                                throw ex
                            } else {
                                false
                            }
                        }
                    } else {
                        logger.i("Skipping configuration for ${provider.flattenToString()}")
                        true
                    }
                if (configured) {
                    communalWidgetDao.addWidget(
                    widgetId = it,
                        widgetId = id,
                        provider = provider,
                        priority = priority,
                    )
                } else {
                    appWidgetHost.deleteAppWidgetId(id)
                }
            }
            logger.i("Added widget ${provider.flattenToString()} at position $priority.")
        }
@@ -182,6 +207,7 @@ constructor(
        }
    }

    @WorkerThread
    private fun mapToContentModel(
        entry: Map.Entry<CommunalItemRank, CommunalWidgetItem>
    ): CommunalWidgetContentModel {
+11 −3

File changed.

Preview size limit exceeded, changes collapsed.

+21 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading