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

Commit 4c3a7c43 authored by Lucas Silva's avatar Lucas Silva
Browse files

Add resize functionality to CommunalEditModeviewModel

When a widget is resized, we also allow them to be re-ordered within the
same function call. This ensures that the resizing and the re-ordering
happen within the same database transaction, to ensure they stay in
sync.

Bug: 368056517
Test: CommunalInteractorTest
Test: CommunalWidgetRepositoryImplTest
Flag: com.android.systemui.communal_widget_resizing
Change-Id: I467663c1f7e34d93bf14413506ef43411c9a4385
parent 0fd4649f
Loading
Loading
Loading
Loading
+17 −2
Original line number Diff line number Diff line
@@ -25,8 +25,10 @@ import android.content.applicationContext
import android.graphics.Bitmap
import android.os.UserHandle
import android.os.userManager
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_COMMUNAL_WIDGET_RESIZING
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.data.repository.fakePackageChangeRepository
import com.android.systemui.common.shared.model.PackageInstallSession
@@ -156,6 +158,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
                        appWidgetId = communalWidgetItemEntry.widgetId,
                        providerInfo = providerInfoA,
                        rank = communalItemRankEntry.rank,
                        spanY = communalWidgetItemEntry.spanY,
                    )
                )

@@ -188,11 +191,13 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
                        appWidgetId = 1,
                        providerInfo = providerInfoA,
                        rank = 1,
                        spanY = 3,
                    ),
                    CommunalWidgetContentModel.Available(
                        appWidgetId = 2,
                        providerInfo = providerInfoB,
                        rank = 2,
                        spanY = 3,
                    ),
                )
        }
@@ -219,11 +224,13 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
                        appWidgetId = 1,
                        providerInfo = providerInfoA,
                        rank = 1,
                        spanY = 3,
                    ),
                    CommunalWidgetContentModel.Available(
                        appWidgetId = 2,
                        providerInfo = providerInfoB,
                        rank = 2,
                        spanY = 3,
                    ),
                )

@@ -238,11 +245,13 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
                        // Verify that provider info updated
                        providerInfo = providerInfoC,
                        rank = 1,
                        spanY = 3,
                    ),
                    CommunalWidgetContentModel.Available(
                        appWidgetId = 2,
                        providerInfo = providerInfoB,
                        rank = 2,
                        spanY = 3,
                    ),
                )
        }
@@ -681,6 +690,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
                        appWidgetId = 1,
                        providerInfo = providerInfoA,
                        rank = 1,
                        spanY = 3,
                    ),
                    CommunalWidgetContentModel.Pending(
                        appWidgetId = 2,
@@ -688,6 +698,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
                        componentName = ComponentName("pk_2", "cls_2"),
                        icon = fakeIcon,
                        user = mainUser,
                        spanY = 3,
                    ),
                )
        }
@@ -723,6 +734,7 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
                        componentName = ComponentName("pk_1", "cls_1"),
                        icon = fakeIcon,
                        user = mainUser,
                        spanY = 3,
                    )
                )

@@ -740,20 +752,23 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
                        appWidgetId = 1,
                        providerInfo = providerInfoA,
                        rank = 1,
                        spanY = 3,
                    )
                )
        }

    @Test
    @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING)
    fun updateWidgetSpanY_updatesWidgetInDaoAndRequestsBackup() =
        testScope.runTest {
            val widgetId = 1
            val newSpanY = 6
            val widgetIdToRankMap = emptyMap<Int, Int>()

            underTest.updateWidgetSpanY(widgetId, newSpanY)
            underTest.resizeWidget(widgetId, newSpanY, widgetIdToRankMap)
            runCurrent()

            verify(communalWidgetDao).updateWidgetSpanY(widgetId, newSpanY)
            verify(communalWidgetDao).resizeWidget(widgetId, newSpanY, widgetIdToRankMap)
            verify(backupManager).dataChanged()
        }

+104 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.pm.UserInfo
import android.os.UserHandle
import android.os.UserManager
import android.os.userManager
import android.platform.test.annotations.EnableFlags
import android.provider.Settings
import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED
import android.widget.RemoteViews
@@ -31,6 +32,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.Flags.FLAG_COMMUNAL_WIDGET_RESIZING
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.communal.data.model.CommunalSmartspaceTimer
@@ -1078,6 +1080,108 @@ class CommunalInteractorTest : SysuiTestCase() {
            assertThat(managedProfileController.isWorkModeEnabled()).isTrue()
        }

    @Test
    @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING)
    fun resizeWidget_withoutUpdatingOrder() =
        testScope.runTest {
            val userInfos = listOf(MAIN_USER_INFO)
            userRepository.setUserInfos(userInfos)
            userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
            runCurrent()

            // Widgets available.
            widgetRepository.addWidget(
                appWidgetId = 1,
                userId = MAIN_USER_INFO.id,
                rank = 0,
                spanY = CommunalContentSize.HALF.span,
            )
            widgetRepository.addWidget(
                appWidgetId = 2,
                userId = MAIN_USER_INFO.id,
                rank = 1,
                spanY = CommunalContentSize.HALF.span,
            )
            widgetRepository.addWidget(
                appWidgetId = 3,
                userId = MAIN_USER_INFO.id,
                rank = 2,
                spanY = CommunalContentSize.HALF.span,
            )

            val widgetContent by collectLastValue(underTest.widgetContent)

            assertThat(widgetContent?.map { it.appWidgetId to it.size })
                .containsExactly(
                    1 to CommunalContentSize.HALF,
                    2 to CommunalContentSize.HALF,
                    3 to CommunalContentSize.HALF,
                )
                .inOrder()

            underTest.resizeWidget(2, CommunalContentSize.FULL.span, emptyMap())

            // Widget 2 should have been resized to FULL
            assertThat(widgetContent?.map { it.appWidgetId to it.size })
                .containsExactly(
                    1 to CommunalContentSize.HALF,
                    2 to CommunalContentSize.FULL,
                    3 to CommunalContentSize.HALF,
                )
                .inOrder()
        }

    @Test
    @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING)
    fun resizeWidget_andUpdateOrder() =
        testScope.runTest {
            val userInfos = listOf(MAIN_USER_INFO)
            userRepository.setUserInfos(userInfos)
            userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
            runCurrent()

            // Widgets available.
            widgetRepository.addWidget(
                appWidgetId = 1,
                userId = MAIN_USER_INFO.id,
                rank = 0,
                spanY = CommunalContentSize.HALF.span,
            )
            widgetRepository.addWidget(
                appWidgetId = 2,
                userId = MAIN_USER_INFO.id,
                rank = 1,
                spanY = CommunalContentSize.HALF.span,
            )
            widgetRepository.addWidget(
                appWidgetId = 3,
                userId = MAIN_USER_INFO.id,
                rank = 2,
                spanY = CommunalContentSize.HALF.span,
            )

            val widgetContent by collectLastValue(underTest.widgetContent)

            assertThat(widgetContent?.map { it.appWidgetId to it.size })
                .containsExactly(
                    1 to CommunalContentSize.HALF,
                    2 to CommunalContentSize.HALF,
                    3 to CommunalContentSize.HALF,
                )
                .inOrder()

            underTest.resizeWidget(2, CommunalContentSize.FULL.span, mapOf(2 to 0, 1 to 1))

            // Widget 2 should have been resized to FULL and moved to the front of the list
            assertThat(widgetContent?.map { it.appWidgetId to it.size })
                .containsExactly(
                    2 to CommunalContentSize.FULL,
                    1 to CommunalContentSize.HALF,
                    3 to CommunalContentSize.HALF,
                )
                .inOrder()
        }

    private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) {
        whenever(kosmos.devicePolicyManager.getKeyguardDisabledFeatures(nullable(), eq(user.id)))
            .thenReturn(disabledFlags)
+11 −2
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import androidx.room.Delete
import androidx.room.Query
import androidx.room.RoomDatabase
import androidx.room.Transaction
import androidx.room.Update
import androidx.sqlite.db.SupportSQLiteDatabase
import com.android.systemui.communal.nano.CommunalHubState
import com.android.systemui.communal.shared.model.CommunalContentSize
@@ -171,8 +172,7 @@ interface CommunalWidgetDao {
    @Query("UPDATE communal_item_rank_table SET rank = :order WHERE uid = :itemUid")
    fun updateItemRank(itemUid: Long, order: Int)

    @Query("UPDATE communal_widget_table SET span_y = :spanY WHERE widget_id = :widgetId")
    fun updateWidgetSpanY(widgetId: Int, spanY: Int)
    @Update fun updateWidget(widget: CommunalWidgetItem)

    @Query("DELETE FROM communal_widget_table") fun clearCommunalWidgetsTable()

@@ -188,6 +188,15 @@ interface CommunalWidgetDao {
        }
    }

    @Transaction
    fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {
        val widget = getWidgetByIdNow(appWidgetId)
        if (widget != null) {
            updateWidget(widget.copy(spanY = spanY))
        }
        updateWidgetOrder(widgetIdToRankMap)
    }

    @Transaction
    fun addWidget(
        widgetId: Int,
+13 −7
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.appwidget.AppWidgetProviderInfo
import android.content.ComponentName
import android.os.UserHandle
import android.os.UserManager
import com.android.systemui.Flags.communalWidgetResizing
import com.android.systemui.common.data.repository.PackageChangeRepository
import com.android.systemui.common.shared.model.PackageInstallSession
import com.android.systemui.communal.data.backup.CommunalBackupUtils
@@ -82,7 +83,7 @@ interface CommunalWidgetRepository {
     *
     * @param widgetIdToRankMap mapping of the widget ids to the rank of the widget.
     */
    fun updateWidgetOrder(widgetIdToRankMap: Map<Int, Int>) {}
    fun updateWidgetOrder(widgetIdToRankMap: Map<Int, Int>)

    /**
     * Restores the database by reading a state file from disk and updating the widget ids according
@@ -96,10 +97,13 @@ interface CommunalWidgetRepository {
    /**
     * Update the spanY of a widget in the database.
     *
     * @param widgetId id of the widget to update.
     * @param appWidgetId id of the widget to update.
     * @param spanY new spanY value for the widget.
     * @param widgetIdToRankMap mapping of the widget ids to its rank. Allows re-ordering widgets
     *   alongside the resize, in case resizing also requires re-ordering. This ensures the
     *   re-ordering is done in the same database transaction as the resize.
     */
    fun updateWidgetSpanY(widgetId: Int, spanY: Int)
    fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>)
}

@SysUISingleton
@@ -135,15 +139,17 @@ constructor(
                    componentName = widget.componentName,
                    rank = rank.rank,
                    providerInfo = providers[widget.widgetId],
                    spanY = widget.spanY,
                )
            }
        }

    override fun updateWidgetSpanY(widgetId: Int, spanY: Int) {
    override fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {
        if (!communalWidgetResizing()) return
        bgScope.launch {
            communalWidgetDao.updateWidgetSpanY(widgetId, spanY)
            communalWidgetDao.resizeWidget(appWidgetId, spanY, widgetIdToRankMap)
            logger.i({ "Updated spanY of widget $int1 to $int2." }) {
                int1 = widgetId
                int1 = appWidgetId
                int2 = spanY
            }
            backupManager.dataChanged()
@@ -445,7 +451,7 @@ constructor(
        val appWidgetId: Int,
        val componentName: String,
        val rank: Int,
        val spanY: Int,
        var providerInfo: AppWidgetProviderInfo? = null,
        var spanY: Int = 3,
    )
}
+6 −0
Original line number Diff line number Diff line
@@ -399,6 +399,10 @@ constructor(
    fun updateWidgetOrder(widgetIdToRankMap: Map<Int, Int>) =
        widgetRepository.updateWidgetOrder(widgetIdToRankMap)

    fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {
        widgetRepository.resizeWidget(appWidgetId, spanY, widgetIdToRankMap)
    }

    /** Request to unpause work profile that is currently in quiet mode. */
    fun unpauseWorkProfile() {
        managedProfileController.setWorkModeEnabled(true)
@@ -449,6 +453,7 @@ constructor(
                            providerInfo = widget.providerInfo,
                            appWidgetHost = appWidgetHost,
                            inQuietMode = isQuietModeEnabled(widget.providerInfo.profile),
                            size = CommunalContentSize.toSize(widget.spanY),
                        )
                    }
                    is CommunalWidgetContentModel.Pending -> {
@@ -457,6 +462,7 @@ constructor(
                            rank = widget.rank,
                            componentName = widget.componentName,
                            icon = widget.icon,
                            size = CommunalContentSize.toSize(widget.spanY),
                        )
                    }
                }
Loading