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

Commit 70940ba9 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Limit usages sent to safety center by user" into main

parents db7e2aea a3cd6b67
Loading
Loading
Loading
Loading
+63 −0
Original line number Diff line number Diff line
@@ -4,6 +4,9 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.UserInfo
import android.os.UserHandle
import android.permission.PermissionGroupUsage
import android.permission.PermissionManager
import android.safetycenter.SafetyCenterManager
import android.view.View
@@ -21,6 +24,7 @@ import com.android.systemui.privacy.PrivacyDialogController
import com.android.systemui.privacy.PrivacyDialogControllerV2
import com.android.systemui.privacy.PrivacyItemController
import com.android.systemui.privacy.logging.PrivacyLogger
import com.android.systemui.settings.UserTracker
import com.android.systemui.shade.data.repository.shadeDialogContextInteractor
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -32,6 +36,8 @@ import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.time.FakeSystemClock
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -81,6 +87,9 @@ class HeaderPrivacyIconsControllerTest : SysuiTestCase() {
    @Mock
    private lateinit var featureFlags: FeatureFlags

    @Mock
    private lateinit var userTracker: UserTracker

    private val uiExecutor = FakeExecutor(FakeSystemClock())
    private val backgroundExecutor = FakeExecutor(FakeSystemClock())
    private lateinit var cameraSlotName: String
@@ -118,6 +127,7 @@ class HeaderPrivacyIconsControllerTest : SysuiTestCase() {
                deviceProvisionedController,
                featureFlags,
                kosmos.shadeDialogContextInteractor,
                userTracker,
        )

        backgroundExecutor.runAllReady()
@@ -269,8 +279,61 @@ class HeaderPrivacyIconsControllerTest : SysuiTestCase() {
        verify(privacyDialogController, never()).showDialog(any(Context::class.java))
    }

    @Test
    fun testPermGroupUsage_filtersOutInactiveUsers() {
        whenever(userTracker.userProfiles).thenReturn(listOf(createUserInfo(USER_ID)))
        whenever(permissionManager.getIndicatorAppOpUsageData(false))
            .thenReturn(listOf(createPermUsage(USER_ID), createPermUsage(OTHER_USER_ID)))
        val usages = controller.permGroupUsage()
        assertEquals(1, usages.size)
        assertEquals(USER_ID, UserHandle.getUserId(usages[0].uid))
    }

    @Test
    fun testPermGroupUsage_alwaysReturnPhoneCallUsage() {
        whenever(userTracker.userProfiles).thenReturn(listOf(createUserInfo(USER_ID)))
        whenever(permissionManager.getIndicatorAppOpUsageData(false))
            .thenReturn(listOf(createPermUsage(OTHER_USER_ID, isPhone = true)))
        val usages = controller.permGroupUsage()
        assertEquals(OTHER_USER_ID, UserHandle.getUserId(usages[0].uid))
    }

    @Test
    fun testPermGroupUsage_returnsProfileUsages() {
        whenever(userTracker.userProfiles)
            .thenReturn(listOf(createUserInfo(USER_ID), createUserInfo(PROFILE_USER_ID)))
        whenever(permissionManager.getIndicatorAppOpUsageData(false))
            .thenReturn(listOf(createPermUsage(USER_ID), createPermUsage(PROFILE_USER_ID)))
        val usages = controller.permGroupUsage()
        assertEquals(2, usages.size)
        assertNotNull(usages.firstOrNull { UserHandle.getUserId(it.uid) == USER_ID })
        assertNotNull(usages.firstOrNull { UserHandle.getUserId(it.uid) == PROFILE_USER_ID })
    }

    private fun createPermUsage(user: Int, isPhone: Boolean = false): PermissionGroupUsage =
        PermissionGroupUsage(
            "",
            UserHandle.getUid(user, 0),
            0,
            "",
            true,
            isPhone,
            null,
            null,
            null,
            "",
        )

    private fun createUserInfo(userId: Int) = UserInfo(userId, "", 0)

    private fun setPrivacyController(micCamera: Boolean, location: Boolean) {
        whenever(privacyItemController.micCameraAvailable).thenReturn(micCamera)
        whenever(privacyItemController.locationAvailable).thenReturn(location)
    }

    companion object {
        const val USER_ID = 0
        const val PROFILE_USER_ID = 1
        const val OTHER_USER_ID = 2
    }
}
+75 −51
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.UserHandle
import android.permission.PermissionGroupUsage
import android.permission.PermissionManager
import android.safetycenter.SafetyCenterManager
@@ -14,6 +15,8 @@ import com.android.internal.logging.UiEventLogger
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.appops.AppOpsController
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.plugins.ActivityStarter
@@ -24,14 +27,13 @@ import com.android.systemui.privacy.PrivacyDialogControllerV2
import com.android.systemui.privacy.PrivacyItem
import com.android.systemui.privacy.PrivacyItemController
import com.android.systemui.privacy.logging.PrivacyLogger
import com.android.systemui.statusbar.phone.StatusIconContainer
import java.util.concurrent.Executor
import javax.inject.Inject
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.UserTracker
import com.android.systemui.shade.ShadeViewProviderModule.Companion.SHADE_HEADER
import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Named

interface ChipVisibilityListener {
@@ -40,15 +42,17 @@ interface ChipVisibilityListener {

/**
 * Controls privacy icons/chip residing in QS header which show up when app is using camera,
 * microphone or location.
 * Manages their visibility depending on privacy signals coming from [PrivacyItemController].
 * microphone or location. Manages their visibility depending on privacy signals coming from
 * [PrivacyItemController].
 *
 * Unlike typical controller extending [com.android.systemui.util.ViewController] this view doesn't
 * observe its attachment state because depending on where it is used, it might be never detached.
 * Instead, parent controller should use [onParentVisible] and [onParentInvisible] to "activate" or
 * "deactivate" this controller.
 */
class HeaderPrivacyIconsController @Inject constructor(
class HeaderPrivacyIconsController
@Inject
constructor(
    private val privacyItemController: PrivacyItemController,
    private val uiEventLogger: UiEventLogger,
    @Named(SHADE_HEADER) private val privacyChip: OngoingPrivacyChip,
@@ -66,6 +70,7 @@ class HeaderPrivacyIconsController @Inject constructor(
    private val deviceProvisionedController: DeviceProvisionedController,
    private val featureFlags: FeatureFlags,
    private val shadeDialogContextInteractor: ShadeDialogContextInteractor,
    private val userTracker: UserTracker,
) {

    var chipVisibilityListener: ChipVisibilityListener? = null
@@ -80,18 +85,20 @@ class HeaderPrivacyIconsController @Inject constructor(
    private val dialogContext: Context
        get() = shadeDialogContextInteractor.context

    private val safetyCenterReceiver = object : BroadcastReceiver() {
    private val safetyCenterReceiver =
        object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                safetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabled()
            }
        }

    val attachStateChangeListener = object : View.OnAttachStateChangeListener {
    val attachStateChangeListener =
        object : View.OnAttachStateChangeListener {
            override fun onViewAttachedToWindow(v: View) {
                broadcastDispatcher.registerReceiver(
                    safetyCenterReceiver,
                    IntentFilter(SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED),
                    executor = backgroundExecutor
                    executor = backgroundExecutor,
                )
            }

@@ -109,7 +116,7 @@ class HeaderPrivacyIconsController @Inject constructor(
            broadcastDispatcher.registerReceiver(
                safetyCenterReceiver,
                IntentFilter(SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED),
                    executor = backgroundExecutor
                executor = backgroundExecutor,
            )
        }

@@ -171,22 +178,39 @@ class HeaderPrivacyIconsController @Inject constructor(

    private fun showSafetyCenter() {
        backgroundExecutor.execute {
            val usage = ArrayList(permGroupUsage())
            val usage = permGroupUsage()
            privacyLogger.logUnfilteredPermGroupUsage(usage)
            val startSafetyCenter = Intent(Intent.ACTION_VIEW_SAFETY_CENTER_QS)
            startSafetyCenter.putParcelableArrayListExtra(PermissionManager.EXTRA_PERMISSION_USAGES,
                usage)
            startSafetyCenter.putParcelableArrayListExtra(
                PermissionManager.EXTRA_PERMISSION_USAGES,
                usage,
            )
            startSafetyCenter.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            uiExecutor.execute {
                activityStarter.startActivity(startSafetyCenter, true,
                    ActivityTransitionAnimator.Controller.fromView(privacyChip))
                activityStarter.startActivity(
                    startSafetyCenter,
                    true,
                    ActivityTransitionAnimator.Controller.fromView(privacyChip),
                )
            }
        }
    }

    @WorkerThread
    private fun permGroupUsage(): List<PermissionGroupUsage> {
        return permissionManager.getIndicatorAppOpUsageData(appOpsController.isMicMuted)
    fun permGroupUsage(): ArrayList<PermissionGroupUsage> {
        val usages =
            ArrayList(permissionManager.getIndicatorAppOpUsageData(appOpsController.isMicMuted))
        val invalidUserUsages = mutableListOf<PermissionGroupUsage>()
        val userProfiles = userTracker.userProfiles
        for (usage in usages) {
            val userId = UserHandle.getUserId(usage.uid)
            if (usage.isPhoneCall || userProfiles.any { it.id == userId }) {
                continue
            }
            invalidUserUsages.add(usage)
        }
        usages.removeAll(invalidUserUsages)
        return usages
    }

    fun onParentInvisible() {