Loading core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +6 −0 Original line number Diff line number Diff line Loading @@ -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 /** Loading packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java +69 −16 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); }); Loading Loading @@ -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. */ Loading @@ -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) { Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java +62 −7 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -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(); } Loading Loading @@ -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, Loading @@ -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(); Loading @@ -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); Loading Loading
core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +6 −0 Original line number Diff line number Diff line Loading @@ -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 /** Loading
packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java +69 −16 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); }); Loading Loading @@ -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. */ Loading @@ -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) { Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java +62 −7 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -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(); } Loading Loading @@ -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, Loading @@ -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(); Loading @@ -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); Loading