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

Commit fada8ebf authored by Kate Montgomery's avatar Kate Montgomery Committed by Android (Google) Code Review
Browse files

Merge "SysUi: Distinguish between location indicator for system app ops vs others."

parents 1eb3b126 18c46bc0
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -163,6 +163,12 @@ public final class SystemUiDeviceConfigFlags {
    public static final String PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED =
            "location_indicators_small_enabled";

    /**
     * Whether to show the location indicator for system apps.
     */
    public static final String PROPERTY_LOCATION_INDICATORS_SHOW_SYSTEM =
            "location_indicators_show_system";

    // Flags related to Assistant

    /**
+69 −16
Original line number Diff line number Diff line
@@ -22,10 +22,14 @@ import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;

import static com.android.settingslib.Utils.updateLocationEnabled;

import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.PermissionChecker;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.location.LocationManager;
import android.os.Handler;
import android.os.Looper;
@@ -68,31 +72,37 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
    private final BootCompleteCache mBootCompleteCache;
    private final UserTracker mUserTracker;
    private final H mHandler;

    private final Handler mBackgroundHandler;
    private final PackageManager mPackageManager;

    private boolean mAreActiveLocationRequests;
    private boolean mShouldDisplayAllAccesses;
    private boolean mShowSystemAccesses;

    @Inject
    public LocationControllerImpl(Context context, AppOpsController appOpsController,
            DeviceConfigProxy deviceConfigProxy,
            @Main Looper mainLooper, @Background Handler backgroundHandler,
            BroadcastDispatcher broadcastDispatcher, BootCompleteCache bootCompleteCache,
            UserTracker userTracker) {
            UserTracker userTracker, PackageManager packageManager) {
        mContext = context;
        mAppOpsController = appOpsController;
        mDeviceConfigProxy = deviceConfigProxy;
        mBootCompleteCache = bootCompleteCache;
        mHandler = new H(mainLooper);
        mUserTracker = userTracker;
        mShouldDisplayAllAccesses = getDeviceConfigSetting();
        mBackgroundHandler = backgroundHandler;
        mPackageManager = packageManager;
        mShouldDisplayAllAccesses = getAllAccessesSetting();
        mShowSystemAccesses = getShowSystemSetting();

        // Register to listen for changes in DeviceConfig settings.
        mDeviceConfigProxy.addOnPropertiesChangedListener(
                DeviceConfig.NAMESPACE_PRIVACY,
                backgroundHandler::post,
                properties -> {
                    mShouldDisplayAllAccesses = getDeviceConfigSetting();
                    mShouldDisplayAllAccesses = getAllAccessesSetting();
                    mShowSystemAccesses = getShowSystemSetting();
                    updateActiveLocationRequests();
                });

@@ -176,11 +186,15 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
                UserHandle.of(userId));
    }

    private boolean getDeviceConfigSetting() {
    private boolean getAllAccessesSetting() {
        return mDeviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED, false);
    }

    private boolean getShowSystemSetting() {
        return mDeviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SHOW_SYSTEM, false);
    }
    /**
     * Returns true if there currently exist active high power location requests.
     */
@@ -202,37 +216,76 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
     * Returns true if there currently exist active location requests.
     */
    @VisibleForTesting
    protected boolean areActiveLocationRequests() {
    protected void areActiveLocationRequests() {
        if (!mShouldDisplayAllAccesses) {
            return false;
            return;
        }
        List<AppOpItem> appOpsItems = mAppOpsController.getActiveAppOps();
        boolean hadActiveLocationRequests = mAreActiveLocationRequests;
        boolean shouldDisplay = false;

        List<AppOpItem> appOpsItems = mAppOpsController.getActiveAppOps();
        final List<UserInfo> profiles = mUserTracker.getUserProfiles();
        final int numItems = appOpsItems.size();
        for (int i = 0; i < numItems; i++) {
            if (appOpsItems.get(i).getCode() == OP_FINE_LOCATION
                    || appOpsItems.get(i).getCode() == OP_COARSE_LOCATION) {
                return true;
                if (mShowSystemAccesses) {
                    shouldDisplay = true;
                } else {
                    shouldDisplay |= !isSystemApp(profiles, appOpsItems.get(i));
                }
            }
        }

        return false;
        mAreActiveLocationRequests = areActiveHighPowerLocationRequests() || shouldDisplay;
        if (mAreActiveLocationRequests != hadActiveLocationRequests) {
            mHandler.sendEmptyMessage(H.MSG_LOCATION_ACTIVE_CHANGED);
        }
    }

    private boolean isSystemApp(List<UserInfo> profiles, AppOpItem item) {
        final String permission = AppOpsManager.opToPermission(item.getCode());
        UserHandle user = UserHandle.getUserHandleForUid(item.getUid());

        // Don't show apps belonging to background users except managed users.
        boolean foundUser = false;
        final int numProfiles = profiles.size();
        for (int i = 0; i < numProfiles; i++) {
            if (profiles.get(i).getUserHandle().equals(user)) {
                foundUser = true;
            }
        }
        if (!foundUser) {
            return true;
        }

        final int permissionFlags = mPackageManager.getPermissionFlags(
                permission, item.getPackageName(), user);
        if (PermissionChecker.checkPermissionForPreflight(mContext, permission,
                PermissionChecker.PID_UNKNOWN, item.getUid(), item.getPackageName())
                == PermissionChecker.PERMISSION_GRANTED) {
            return (permissionFlags
                    & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED)
                    == 0;
        } else {
            return (permissionFlags
                    & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED) == 0;
        }
    }

    // Reads the active location requests from either OP_MONITOR_HIGH_POWER_LOCATION,
    // OP_FINE_LOCATION, or OP_COARSE_LOCATION and updates the status view if necessary.
    private void updateActiveLocationRequests() {
        boolean hadActiveLocationRequests = mAreActiveLocationRequests;
        if (mShouldDisplayAllAccesses) {
            mAreActiveLocationRequests =
                    areActiveHighPowerLocationRequests() || areActiveLocationRequests();
            mBackgroundHandler.post(this::areActiveLocationRequests);
        } else {
            boolean hadActiveLocationRequests = mAreActiveLocationRequests;
            mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
        }
            if (mAreActiveLocationRequests != hadActiveLocationRequests) {
                mHandler.sendEmptyMessage(H.MSG_LOCATION_ACTIVE_CHANGED);
            }
        }
    }

    @Override
    public void onReceive(Context context, Intent intent) {
+62 −7
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.when;

import android.app.AppOpsManager;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.location.LocationManager;
import android.os.Handler;
import android.os.UserHandle;
@@ -68,6 +69,8 @@ public class LocationControllerImplTest extends SysuiTestCase {
        MockitoAnnotations.initMocks(this);
        when(mUserTracker.getUserId()).thenReturn(UserHandle.USER_SYSTEM);
        when(mUserTracker.getUserHandle()).thenReturn(UserHandle.SYSTEM);
        when(mUserTracker.getUserProfiles())
                .thenReturn(ImmutableList.of(new UserInfo(0, "name", 0)));
        mDeviceConfigProxy = new DeviceConfigProxyFake();

        mTestableLooper = TestableLooper.get(this);
@@ -78,7 +81,8 @@ public class LocationControllerImplTest extends SysuiTestCase {
                new Handler(mTestableLooper.getLooper()),
                mock(BroadcastDispatcher.class),
                mock(BootCompleteCache.class),
                mUserTracker);
                mUserTracker,
                mContext.getPackageManager());

        mTestableLooper.processAllMessages();
    }
@@ -161,17 +165,38 @@ public class LocationControllerImplTest extends SysuiTestCase {
    @Test
    public void testCallbackNotified_additionalOps() {
        LocationChangeCallback callback = mock(LocationChangeCallback.class);

        mLocationController.addCallback(callback);
        mDeviceConfigProxy.setProperty(
                DeviceConfig.NAMESPACE_PRIVACY,
                SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED,
                "true",
                true);
        mTestableLooper.processAllMessages();

        when(mAppOpsController.getActiveAppOps())
                .thenReturn(ImmutableList.of(
                        new AppOpItem(AppOpsManager.OP_FINE_LOCATION, 0,
                                "com.google.android.googlequicksearchbox",
                                System.currentTimeMillis())));
        mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
                "com.google.android.googlequicksearchbox", true);

        mTestableLooper.processAllMessages();

        mLocationController.onReceive(mContext, new Intent(LocationManager.MODE_CHANGED_ACTION));
        verify(callback, times(1)).onLocationActiveChanged(true);

        when(mAppOpsController.getActiveAppOps()).thenReturn(ImmutableList.of());
        mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
                "com.google.android.googlequicksearchbox", false);
        mTestableLooper.processAllMessages();

        verify(callback, times(2)).onLocationSettingsChanged(anyBoolean());
        verify(callback, times(1)).onLocationActiveChanged(false);
    }

    @Test
    public void testCallbackNotified_additionalOps_shouldShowSystem() {
        LocationChangeCallback callback = mock(LocationChangeCallback.class);
        mLocationController.addCallback(callback);
        mDeviceConfigProxy.setProperty(
                DeviceConfig.NAMESPACE_PRIVACY,
                SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED,
@@ -181,10 +206,40 @@ public class LocationControllerImplTest extends SysuiTestCase {

        when(mAppOpsController.getActiveAppOps())
                .thenReturn(ImmutableList.of(
                        new AppOpItem(AppOpsManager.OP_FINE_LOCATION, 0, "",
                        new AppOpItem(AppOpsManager.OP_FINE_LOCATION, 0,
                                "com.google.android.gms",
                                System.currentTimeMillis())));
        mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
                "", true);
                "com.google.android.gms", true);

        mTestableLooper.processAllMessages();

        verify(callback, times(0)).onLocationActiveChanged(true);
    }


    @Test
    public void testCallbackNotified_additionalOps_shouldNotShowSystem() {
        LocationChangeCallback callback = mock(LocationChangeCallback.class);
        mLocationController.addCallback(callback);
        mDeviceConfigProxy.setProperty(
                DeviceConfig.NAMESPACE_PRIVACY,
                SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED,
                "true",
                true);
        mDeviceConfigProxy.setProperty(
                DeviceConfig.NAMESPACE_PRIVACY,
                SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SHOW_SYSTEM,
                "true",
                true);
        mTestableLooper.processAllMessages();

        when(mAppOpsController.getActiveAppOps())
                .thenReturn(ImmutableList.of(
                        new AppOpItem(AppOpsManager.OP_FINE_LOCATION, 0, "com.google.android.gms",
                                System.currentTimeMillis())));
        mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
                "com.google.android.gms", true);

        mTestableLooper.processAllMessages();

@@ -192,7 +247,7 @@ public class LocationControllerImplTest extends SysuiTestCase {

        when(mAppOpsController.getActiveAppOps()).thenReturn(ImmutableList.of());
        mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
                "", false);
                "com.google.android.gms", false);
        mTestableLooper.processAllMessages();

        verify(callback, times(1)).onLocationActiveChanged(false);