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

This commit is contained in:
Kate Montgomery
2022-01-21 00:28:58 +00:00
committed by Android (Google) Code Review
3 changed files with 144 additions and 30 deletions

View File

@@ -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
/**

View File

@@ -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,35 +216,74 @@ 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);
if (mAreActiveLocationRequests != hadActiveLocationRequests) {
mHandler.sendEmptyMessage(H.MSG_LOCATION_ACTIVE_CHANGED);
}
}
}

View File

@@ -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,7 @@ public class LocationControllerImplTest extends SysuiTestCase {
@Test
public void testCallbackNotified_additionalOps() {
LocationChangeCallback callback = mock(LocationChangeCallback.class);
mLocationController.addCallback(callback);
mTestableLooper.processAllMessages();
mLocationController.onReceive(mContext, new Intent(LocationManager.MODE_CHANGED_ACTION));
mTestableLooper.processAllMessages();
verify(callback, times(2)).onLocationSettingsChanged(anyBoolean());
mDeviceConfigProxy.setProperty(
DeviceConfig.NAMESPACE_PRIVACY,
SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED,
@@ -181,10 +175,11 @@ 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.googlequicksearchbox",
System.currentTimeMillis())));
mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
"", true);
"com.google.android.googlequicksearchbox", true);
mTestableLooper.processAllMessages();
@@ -192,7 +187,67 @@ public class LocationControllerImplTest extends SysuiTestCase {
when(mAppOpsController.getActiveAppOps()).thenReturn(ImmutableList.of());
mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
"", false);
"com.google.android.googlequicksearchbox", false);
mTestableLooper.processAllMessages();
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,
"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();
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();
verify(callback, times(1)).onLocationActiveChanged(true);
when(mAppOpsController.getActiveAppOps()).thenReturn(ImmutableList.of());
mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
"com.google.android.gms", false);
mTestableLooper.processAllMessages();
verify(callback, times(1)).onLocationActiveChanged(false);