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

Commit ca175465 authored by Bryce Lee's avatar Bryce Lee
Browse files

Require non-partial process user before checking device policy.

This changelist predicates reaching out to device policy for communal
logic until the process user is fully created. This is done to ensure
user static permissions (such as INTERACT_ACROSS_USERS_FULL) are in
place.

Fix: 407646672
Test: atest CommunalSettingsInteractorTest#allowedForCurrentUserByDevicePolicy_reportsFalseWithPartialUserInfo
Flag: EXEMPT bugfix
Change-Id: I536ab5d112d8c25dfcb42021e1e4b1ce35d6dcfb
parent 2c90268f
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.settings.fakeSettings
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
@@ -102,6 +103,20 @@ class CommunalSettingsInteractorTest : SysuiTestCase() {
            assertEquals(startCondition, WhenToStartHub.WHILE_CHARGING)
        }

    @Test
    fun allowedForCurrentUserByDevicePolicy_reportsFalseWithPartialUserInfo() =
        kosmos.runTest {
            val lastValue by collectLastValue(underTest.allowedForCurrentUserByDevicePolicy)

            assertThat(lastValue).isTrue()

            val userInfo = UserInfo(fakeUserRepository.getMainUser())
            userInfo.partial = true
            fakeUserRepository.setUserInfos(listOf(userInfo))

            assertThat(lastValue).isFalse()
        }

    private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) {
        whenever(
                kosmos.devicePolicyManager.getKeyguardDisabledFeatures(
+13 −4
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import com.android.systemui.communal.shared.model.CommunalBackgroundType
import com.android.systemui.communal.shared.model.WhenToStartHub
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.process.domain.interactor.ProcessInteractor
import com.android.systemui.settings.UserTracker
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
@@ -52,6 +53,7 @@ constructor(
    @Background private val bgDispatcher: CoroutineDispatcher,
    @Background private val bgExecutor: Executor,
    private val repository: CommunalSettingsRepository,
    private val processInteractor: ProcessInteractor,
    userInteractor: SelectedUserInteractor,
    private val userTracker: UserTracker,
) {
@@ -82,7 +84,7 @@ constructor(
    /** Whether communal hub is allowed by device policy for the current user */
    val allowedForCurrentUserByDevicePolicy: Flow<Boolean> =
        userInteractor.selectedUserInfo.flatMapLatestConflated { user ->
            repository.getAllowedByDevicePolicy(user)
            getAllowedByDevicePolicy(user)
        }

    /** Whether the hub is enabled for the current user */
@@ -159,9 +161,7 @@ constructor(
        workProfileUserInfoCallbackFlow
            .flatMapLatest { workProfile ->
                workProfile?.let {
                    repository.getAllowedByDevicePolicy(it).map { allowed ->
                        if (!allowed) it else null
                    }
                    getAllowedByDevicePolicy(it).map { allowed -> if (!allowed) it else null }
                } ?: flowOf(null)
            }
            .stateIn(
@@ -169,4 +169,13 @@ constructor(
                started = SharingStarted.WhileSubscribed(),
                initialValue = null,
            )

    private fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> =
        processInteractor.processUserReady.flatMapLatestConflated { ready ->
            if (ready) {
                repository.getAllowedByDevicePolicy(user)
            } else {
                flowOf(false)
            }
        }
}
+48 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.process.domain.interactor

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.process.ProcessWrapper
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn

@SysUISingleton
class ProcessInteractor
@Inject
constructor(
    userRepository: UserRepository,
    private val processWrapper: ProcessWrapper,
    @Background val bgDispatcher: CoroutineDispatcher,
) {
    val processUserReady: Flow<Boolean> =
        userRepository.userInfos
            .flatMapLatestConflated { infos ->
                flowOf(
                    infos.count { info ->
                        !info.partial && info.userHandle == processWrapper.myUserHandle()
                    } > 0
                )
            }
            .flowOn(bgDispatcher)
}
+2 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.process.domain.interactor.processInteractor
import com.android.systemui.settings.userTracker
import com.android.systemui.user.domain.interactor.selectedUserInteractor

@@ -32,6 +33,7 @@ val Kosmos.communalSettingsInteractor by Fixture {
        bgDispatcher = testDispatcher,
        repository = communalSettingsRepository,
        userInteractor = selectedUserInteractor,
        processInteractor = processInteractor,
        userTracker = userTracker,
    )
}
+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.process.domain.interactor

import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.process.processWrapper
import com.android.systemui.user.data.repository.userRepository

val Kosmos.processInteractor by Fixture {
    ProcessInteractor(
        userRepository = userRepository,
        processWrapper = processWrapper,
        bgDispatcher = testDispatcher,
    )
}
Loading