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

Commit 7548806d authored by Darrell Shi's avatar Darrell Shi
Browse files

Introduce GlanceableHubWidgetManagerService

This change introduces the GlanceableHubWidgetManagerService and
GlanceableHubWidgetManager for communication between the headless system
user and the foreground user.

This change also includes logic for binding and unbinding from the
service, which is managed by the ServiceWatcher. The rest of the
functionality will come in subsequent CLs.

Test: atest CommunalAppWidgetHostStartableTest
Bug: 357621815
Flag: com.android.systemui.secondary_user_widget_host
Change-Id: I1b90219705ab434a37cb8c10e4b91a687b8806a3
parent 11a57e35
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -1015,6 +1015,10 @@
            android:exported="false">
        </activity>

        <service
            android:name="com.android.systemui.communal.widgets.GlanceableHubWidgetManagerService"
            android:exported="false" />

        <!-- Doze with notifications, run in main sysui process for every user  -->
        <service
            android:name=".doze.DozeService"
+47 −8
Original line number Diff line number Diff line
@@ -24,10 +24,14 @@ import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
import com.android.systemui.communal.shared.model.FakeGlanceableHubMultiUserHelper
import com.android.systemui.communal.shared.model.fakeGlanceableHubMultiUserHelper
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
@@ -58,6 +62,9 @@ class CommunalAppWidgetHostStartableTest : SysuiTestCase() {
    @Mock private lateinit var appWidgetHost: CommunalAppWidgetHost
    @Mock private lateinit var communalWidgetHost: CommunalWidgetHost

    private lateinit var widgetManager: GlanceableHubWidgetManager
    private lateinit var helper: FakeGlanceableHubMultiUserHelper

    private lateinit var appWidgetIdToRemove: MutableSharedFlow<Int>

    private lateinit var underTest: CommunalAppWidgetHostStartable
@@ -69,17 +76,23 @@ class CommunalAppWidgetHostStartableTest : SysuiTestCase() {
        kosmos.fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, true)
        mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB)

        widgetManager = kosmos.mockGlanceableHubWidgetManager
        helper = kosmos.fakeGlanceableHubMultiUserHelper
        appWidgetIdToRemove = MutableSharedFlow()
        whenever(appWidgetHost.appWidgetIdToRemove).thenReturn(appWidgetIdToRemove)

        underTest =
            CommunalAppWidgetHostStartable(
                appWidgetHost,
                communalWidgetHost,
                kosmos.communalInteractor,
                kosmos.fakeUserTracker,
                { appWidgetHost },
                { communalWidgetHost },
                { kosmos.communalInteractor },
                { kosmos.communalSettingsInteractor },
                { kosmos.keyguardInteractor },
                { kosmos.fakeUserTracker },
                kosmos.applicationCoroutineScope,
                kosmos.testDispatcher,
                { widgetManager },
                helper,
            )
    }

@@ -211,7 +224,7 @@ class CommunalAppWidgetHostStartableTest : SysuiTestCase() {
                fakeCommunalWidgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id)
                fakeCommunalWidgetRepository.addPendingWidget(
                    appWidgetId = 2,
                    userId = USER_INFO_WORK.id
                    userId = USER_INFO_WORK.id,
                )
                fakeCommunalWidgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id)

@@ -246,16 +259,42 @@ class CommunalAppWidgetHostStartableTest : SysuiTestCase() {
            }
        }

    private suspend fun setCommunalAvailable(available: Boolean) =
    @Test
    fun onStartHeadlessSystemUser_registerWidgetManager_whenCommunalIsAvailable() =
        with(kosmos) {
            testScope.runTest {
                helper.setIsInHeadlessSystemUser(true)
                underTest.start()
                runCurrent()
                verify(widgetManager, never()).register()
                verify(widgetManager, never()).unregister()

                // Binding to the service does not require keyguard showing
                setCommunalAvailable(true, setKeyguardShowing = false)
                runCurrent()
                verify(widgetManager).register()

                setCommunalAvailable(false)
                runCurrent()
                verify(widgetManager).unregister()
            }
        }

    private suspend fun setCommunalAvailable(
        available: Boolean,
        setKeyguardShowing: Boolean = true,
    ) =
        with(kosmos) {
            fakeKeyguardRepository.setIsEncryptedOrLockdown(false)
            fakeUserRepository.setSelectedUserInfo(MAIN_USER_INFO)
            if (setKeyguardShowing) {
                fakeKeyguardRepository.setKeyguardShowing(true)
            }
            val settingsValue = if (available) 1 else 0
            fakeSettings.putIntForUser(
                Settings.Secure.GLANCEABLE_HUB_ENABLED,
                settingsValue,
                MAIN_USER_INFO.id
                MAIN_USER_INFO.id,
            )
        }

+10 −7
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@ import com.android.systemui.communal.domain.interactor.CommunalSceneTransitionIn
import com.android.systemui.communal.shared.log.CommunalMetricsLogger
import com.android.systemui.communal.shared.log.CommunalStatsLogProxyImpl
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper
import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelperImpl
import com.android.systemui.communal.util.CommunalColors
import com.android.systemui.communal.util.CommunalColorsImpl
import com.android.systemui.communal.widgets.CommunalWidgetModule
@@ -65,6 +67,7 @@ import kotlinx.coroutines.CoroutineScope
            CommunalSettingsRepositoryModule::class,
            CommunalSmartspaceRepositoryModule::class,
            CommunalStartableModule::class,
            GlanceableHubWidgetManagerModule::class,
        ]
)
interface CommunalModule {
@@ -91,6 +94,11 @@ interface CommunalModule {
        impl: CommunalSceneTransitionInteractor
    ): CoreStartable

    @Binds
    fun bindGlanceableHubMultiUserHelper(
        impl: GlanceableHubMultiUserHelperImpl
    ): GlanceableHubMultiUserHelper

    companion object {
        const val LOGGABLE_PREFIXES = "loggable_prefixes"
        const val LAUNCHER_PACKAGE = "launcher_package"
@@ -106,19 +114,14 @@ interface CommunalModule {
                    sceneKeys = listOf(CommunalScenes.Blank, CommunalScenes.Communal),
                    initialSceneKey = CommunalScenes.Blank,
                    navigationDistances =
                        mapOf(
                            CommunalScenes.Blank to 0,
                            CommunalScenes.Communal to 1,
                        ),
                        mapOf(CommunalScenes.Blank to 0, CommunalScenes.Communal to 1),
                )
            return SceneDataSourceDelegator(applicationScope, config)
        }

        @Provides
        @SysUISingleton
        fun providesCommunalBackupUtils(
            @Application context: Context,
        ): CommunalBackupUtils {
        fun providesCommunalBackupUtils(@Application context: Context): CommunalBackupUtils {
            return CommunalBackupUtils(context)
        }

+2 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.systemui.communal.CommunalOngoingContentStartable
import com.android.systemui.communal.CommunalSceneStartable
import com.android.systemui.communal.log.CommunalLoggerStartable
import com.android.systemui.communal.widgets.CommunalAppWidgetHostStartable
import com.android.systemui.dagger.qualifiers.PerUser
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
@@ -48,6 +49,7 @@ interface CommunalStartableModule {

    @Binds
    @IntoMap
    @PerUser
    @ClassKey(CommunalAppWidgetHostStartable::class)
    fun bindCommunalAppWidgetHostStartable(impl: CommunalAppWidgetHostStartable): CoreStartable

+38 −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.dagger

import com.android.server.servicewatcher.ServiceWatcher.ServiceSupplier
import com.android.systemui.communal.widgets.GlanceableHubWidgetManagerServiceInfo
import com.android.systemui.communal.widgets.GlanceableHubWidgetManagerServiceSupplier
import com.android.systemui.communal.widgets.GlanceableHubWidgetManagerServiceWatcherFactoryImpl
import com.android.systemui.communal.widgets.ServiceWatcherFactory
import dagger.Binds
import dagger.Module

@Module
interface GlanceableHubWidgetManagerModule {
    @Binds
    fun bindServiceSupplier(
        impl: GlanceableHubWidgetManagerServiceSupplier
    ): ServiceSupplier<GlanceableHubWidgetManagerServiceInfo?>

    @Binds
    fun bindServiceWatcherFactory(
        impl: GlanceableHubWidgetManagerServiceWatcherFactoryImpl
    ): ServiceWatcherFactory<GlanceableHubWidgetManagerServiceInfo?>
}
Loading