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

Commit 23c26269 authored by Yu-Han Yang's avatar Yu-Han Yang
Browse files

Add location op apps to "Recent app use" UI

- Rename the title as "Microphone, Camera & Location" (from "Microphone
  & Camera)
- Exclude the system apps and background apps for Location Op usage

Bug: 419834493
Test: on device
Flag: android.location.flags.location_indicators_enabled
Change-Id: I9a16993da8289542597adbe29963d13d201c8093
parent cf26bb7d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1329,7 +1329,7 @@ public final class PermissionManager {
        // Lazily initialize the usage helper
        initializeUsageHelper();
        boolean includeMicrophoneUsage = !micMuted;
        return mUsageHelper.getOpUsageDataByDevice(includeMicrophoneUsage,
        return mUsageHelper.getOpUsageDataForIndicatorsByDevice(includeMicrophoneUsage,
                VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
    }

+86 −3
Original line number Diff line number Diff line
@@ -40,10 +40,12 @@ import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_AC

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.companion.virtual.VirtualDevice;
import android.companion.virtual.VirtualDeviceManager;
import android.content.Context;
import android.content.PermissionChecker;
import android.content.pm.ApplicationInfo;
import android.content.pm.Attribution;
import android.content.pm.PackageInfo;
@@ -54,6 +56,7 @@ import android.location.LocationManager;
import android.media.AudioManager;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.permission.flags.Flags;
import android.provider.DeviceConfig;
import android.telephony.TelephonyManager;
@@ -103,7 +106,8 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis

    private static boolean shouldShowIndicators() {
        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                PROPERTY_CAMERA_MIC_ICONS_ENABLED, true);
                PROPERTY_CAMERA_MIC_ICONS_ENABLED, true)
                || android.location.flags.Flags.locationIndicatorsEnabled();
    }

    private static long getRecentThreshold(Long now) {
@@ -116,6 +120,11 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
                RUNNING_ACCESS_TIME_MS, DEFAULT_RUNNING_TIME_MS);
    }

    private static final List<String> LOCATION_OPS = List.of(
            OPSTR_COARSE_LOCATION,
            OPSTR_FINE_LOCATION
    );

    private static final List<String> MIC_OPS = List.of(
            OPSTR_PHONE_CALL_MICROPHONE,
            OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO,
@@ -274,8 +283,10 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
    /**
     * Return Op usage for CAMERA, LOCATION AND MICROPHONE for all packages for a device.
     * The returned data is to power privacy indicator.
     *
     * <p>The system apps and background apps are excluded for LOCATION Op usage.
     */
    public @NonNull List<PermissionGroupUsage> getOpUsageDataByDevice(
    public @NonNull List<PermissionGroupUsage> getOpUsageDataForIndicatorsByDevice(
            boolean includeMicrophoneUsage, String deviceId) {
        List<PermissionGroupUsage> usages = new ArrayList<>();

@@ -287,6 +298,9 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
        if (includeMicrophoneUsage) {
            ops.addAll(MIC_OPS);
        }
        if (android.location.flags.Flags.locationIndicatorsEnabled()) {
            ops.addAll(LOCATION_OPS);
        }

        Map<String, List<OpUsage>> rawUsages = getOpUsagesByDevice(ops, deviceId);

@@ -367,7 +381,7 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis

            for (int index = 0; index < persistentDeviceIds.size(); index++) {
                allUsages.addAll(
                        getOpUsageDataByDevice(includeMicrophoneUsage,
                        getOpUsageDataForIndicatorsByDevice(includeMicrophoneUsage,
                                persistentDeviceIds.valueAt(index)));
            }
        }
@@ -455,12 +469,75 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
                mContext.getSystemService(LocationManager.class)).isProviderPackage(packageName);
    }

    /**
     * Returns true if the package is a system app.
     *
     * <p>TODO(b/422799135): refactor isSystemApp() and isBackgroundApp(). Before this is fixed,
     *           make sure to update AppOpsPrivacyItemMonitor when changing this method
     */
    private boolean isSystemApp(String op, String packageName, UserHandle user, int uid) {
        UserManager userManager = mContext.getSystemService(UserManager.class);
        if (userManager != null) {
            // Don't show apps belonging to background users except managed users.
            boolean foundUser = false;
            List<UserHandle> userProfiles = userManager.getUserProfiles();
            for (UserHandle profile : userProfiles) {
                if (profile.equals(user)) {
                    foundUser = true;
                    break;
                }
            }
            if (!foundUser) {
                return true;
            }
        }

        String permission = mAppOpsManager.opToPermission(op);
        int permissionFlags = mPkgManager.getPermissionFlags(permission, packageName, user);
        if (PermissionChecker.checkPermissionForPreflight(
                mContext,
                permission,
                PermissionChecker.PID_UNKNOWN,
                uid,
                packageName) == PermissionChecker.PERMISSION_GRANTED) {
            return (permissionFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED)
                    == 0;
        } else {
            return (permissionFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED)
                    == 0;
        }
    }

    /**
     * Returns true if it is a background app
     *
     * <p>TODO(b/422799135): refactor isSystemApp() and isBackgroundApp(). Before this is fixed,
     *           make sure to update AppOpsPrivacyItemMonitor when changing this method
     */
    private boolean isBackgroundApp(int uid) {
        ActivityManager activityManager =  mContext.getSystemService(ActivityManager.class);
        List<ActivityManager.RunningAppProcessInfo> runningAppProcesses =
                activityManager.getRunningAppProcesses();
        if (runningAppProcesses == null) {
            return false;
        }
        for (ActivityManager.RunningAppProcessInfo processInfo : runningAppProcesses) {
            if (processInfo.uid == uid) {
                return processInfo.importance
                        > ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
            }
        }
        return false;
    }

    /**
     * Get the raw usages from the system, and then parse out the ones that are not recent enough,
     * determine which permission group each belongs in, and removes duplicates (if the same app
     * uses multiple permissions of the same group). Stores the package name, attribution tag, user,
     * running/recent info, if the usage is a phone call, per permission group.
     *
     * <p>The system apps and background apps are excluded for location Op usage.
     *
     * @param opNames a list of op names to get usage for
     * @param deviceId which device to get op usage for
     * @return A map of permission group -> list of usages that are recent or running
@@ -532,6 +609,12 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
                    }

                    String permGroupName = getGroupForOp(op);
                    if (LOCATION.equals(permGroupName)) {
                        if (isSystemApp(op, packageName, user, uid) || isBackgroundApp(uid)) {
                            // Remove the system & background apps for location op
                            continue;
                        }
                    }
                    OpUsage usage = new OpUsage(packageName, attributionTag, op, uid,
                            lastAccessTime, isRunning, proxyUsage);

+7 −7
Original line number Diff line number Diff line
@@ -24,8 +24,8 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.TextView
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.res.R
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -62,7 +62,7 @@ class PrivacyDialogV2Test : SysuiTestCase() {
            isPhoneCall: Boolean = false,
            isService: Boolean = false,
            permGroupName: String = TEST_PERM_GROUP,
            navigationIntent: Intent = TEST_INTENT
            navigationIntent: Intent = TEST_INTENT,
        ) =
            PrivacyDialogV2.PrivacyElement(
                type,
@@ -77,7 +77,7 @@ class PrivacyDialogV2Test : SysuiTestCase() {
                isPhoneCall,
                isService,
                permGroupName,
                navigationIntent
                navigationIntent,
            )
    }

@@ -184,7 +184,7 @@ class PrivacyDialogV2Test : SysuiTestCase() {
        val list =
            listOf(
                createPrivacyElement(type = PrivacyType.TYPE_CAMERA, isActive = true),
                createPrivacyElement()
                createPrivacyElement(),
            )
        dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard)

@@ -275,7 +275,7 @@ class PrivacyDialogV2Test : SysuiTestCase() {
                createPrivacyElement(
                    attributionLabel = "For subattribution",
                    isActive = true,
                    isService = true
                    isService = true,
                )
            )
        dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard)
@@ -293,7 +293,7 @@ class PrivacyDialogV2Test : SysuiTestCase() {
                createPrivacyElement(
                    attributionLabel = "For subattribution",
                    proxyLabel = "proxy label",
                    isActive = true
                    isActive = true,
                )
            )
        dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard)
@@ -308,7 +308,7 @@ class PrivacyDialogV2Test : SysuiTestCase() {
        dialog = PrivacyDialogV2(context, list, manageApp, closeApp, openPrivacyDashboard)
        dialog.show()

        assertThat(dialog.window?.attributes?.title).isEqualTo("Microphone & Camera")
        assertThat(dialog.window?.attributes?.title).isEqualTo("Microphone, Camera & Location")
    }

    @Test
+1 −1
Original line number Diff line number Diff line
@@ -3913,7 +3913,7 @@
    <string name="connected_display_icon_desc">Display connected</string>

    <!-- Title of the privacy dialog, shown for active / recent app usage of some phone sensors [CHAR LIMIT=30] -->
    <string name="privacy_dialog_title">Microphone &amp; Camera</string>
    <string name="privacy_dialog_title">Microphone, Camera &amp; Location</string>
    <!-- Subtitle of the privacy dialog, shown for active / recent app usage of some phone sensors [CHAR LIMIT=NONE] -->
    <string name="privacy_dialog_summary">Recent app use</string>
    <!-- Label of the secondary button of the privacy dialog, used to check recent app usage of phone sensors [CHAR LIMIT=30] -->
+12 −0
Original line number Diff line number Diff line
@@ -267,6 +267,12 @@ constructor(
        return true
    }

    /**
     * Returns true if the package is a system app.
     *
     * <p>TODO(b/422799135): refactor isSystemApp() and isBackgroundApp(). Before this is fixed,
     * make sure to update PermissionUsageHelper when changing this method.
     */
    private fun isSystemApp(item: AppOpItem): Boolean {
        val user = UserHandle.getUserHandleForUid(item.uid)

@@ -299,6 +305,12 @@ constructor(
        }
    }

    /**
     * Returns true if it is a background app
     *
     * <p>TODO(b/422799135): refactor isSystemApp() and isBackgroundApp(). Before this is fixed,
     * make sure to update PermissionUsageHelper when changing this method.
     */
    private fun isBackgroundApp(item: AppOpItem): Boolean {
        for (processInfo in activityManager.runningAppProcesses) {
            if (processInfo.uid == item.uid) {