diff options
6 files changed, 89 insertions, 7 deletions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 759979100483..73a40cfe07e8 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -8951,7 +8951,8 @@ public class DevicePolicyManager { * * <strong>Note: Starting from Android R, apps should no longer call this method with the * setting {@link android.provider.Settings.Secure#LOCATION_MODE}, which is deprecated. Instead, - * device owners should call {@link #setLocationEnabled(ComponentName, boolean)}. + * device owners should call {@link #setLocationEnabled(ComponentName, boolean)}. This will be + * enforced for all apps targeting Android R or above. * </strong> * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. @@ -8961,6 +8962,7 @@ public class DevicePolicyManager { */ public void setSecureSetting(@NonNull ComponentName admin, String setting, String value) { throwIfParentInstance("setSecureSetting"); + if (mService != null) { try { mService.setSecureSetting(admin, setting, value); diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a54566cfed17..08c840380fe5 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -414,6 +414,14 @@ logging. [CHAR LIMIT=NONE]--> <string name="network_logging_notification_text">Your organization manages this device and may monitor network traffic. Tap for details.</string> + <!-- Content title for a notification. This notification indicates that the device owner has + changed the location settings. [CHAR LIMIT=NONE] --> + <string name="location_changed_notification_title">Location settings changed by your admin</string> + <!-- Content text for a notification. Tapping opens device location settings. + [CHAR LIMIT=NONE] --> + <string name="location_changed_notification_text">Tap to see your location settings.</string> + + <!-- Factory reset warning dialog strings--> <skip /> <!-- Shows up in the dialog's title to warn about an impeding factory reset. [CHAR LIMIT=NONE] --> <string name="factory_reset_warning">Your device will be erased</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 2453bb18577f..dc5213324a81 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1213,6 +1213,8 @@ <java-symbol type="string" name="device_ownership_relinquished" /> <java-symbol type="string" name="network_logging_notification_title" /> <java-symbol type="string" name="network_logging_notification_text" /> + <java-symbol type="string" name="location_changed_notification_title" /> + <java-symbol type="string" name="location_changed_notification_text" /> <java-symbol type="string" name="personal_apps_suspended_notification_title" /> <java-symbol type="string" name="personal_apps_suspended_notification_text" /> <java-symbol type="string" name="factory_reset_warning" /> diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index 54b420191deb..63dd99e215ab 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -244,6 +244,10 @@ message SystemMessage { // Package: android NOTE_SOFTAP_AUTO_DISABLED = 58; + // Notify the user that their admin has changed location settings. + // Package: android + NOTE_LOCATION_CHANGED = 59; + // ADD_NEW_IDS_ABOVE_THIS_LINE // Legacy IDs with arbitrary values appear below // Legacy IDs existed as stable non-conflicting constants prior to the O release diff --git a/services/core/java/com/android/server/location/TEST_MAPPING b/services/core/java/com/android/server/location/TEST_MAPPING index 2e21fa67a967..214d2f3f5646 100644 --- a/services/core/java/com/android/server/location/TEST_MAPPING +++ b/services/core/java/com/android/server/location/TEST_MAPPING @@ -1,10 +1,19 @@ { "presubmit": [ { + "name": "CtsLocationFineTestCases" + }, + { "name": "CtsLocationCoarseTestCases" }, { "name": "CtsLocationNoneTestCases" + }, + { + "name": "FrameworksMockingServicesTests", + "options": [{ + "include-filter": "com.android.server.location" + }] } ] }
\ No newline at end of file diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 553ec4201cc2..9bc1f57f26b4 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -560,6 +560,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) private static final long ADMIN_APP_PASSWORD_COMPLEXITY = 123562444L; + /** + * Admin apps targeting Android R+ may not use + * {@link android.app.admin.DevicePolicyManager#setSecureSetting} to change the deprecated + * {@link android.provider.Settings.Secure#LOCATION_MODE} setting. Instead they should use + * {@link android.app.admin.DevicePolicyManager#setLocationEnabled}. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) + private static final long USE_SET_LOCATION_ENABLED = 117835097L; + final Context mContext; final Injector mInjector; final IPackageManager mIPackageManager; @@ -11558,13 +11568,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public void setLocationEnabled(ComponentName who, boolean locationEnabled) { - Objects.requireNonNull(who, "ComponentName is null"); - enforceDeviceOwner(who); + enforceDeviceOwner(Objects.requireNonNull(who)); - UserHandle userHandle = mInjector.binderGetCallingUserHandle(); - mInjector.binderWithCleanCallingIdentity( - () -> mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled, - userHandle)); + UserHandle user = mInjector.binderGetCallingUserHandle(); + + mInjector.binderWithCleanCallingIdentity(() -> { + boolean wasLocationEnabled = mInjector.getLocationManager().isLocationEnabledForUser( + user); + mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled, user); + + // make a best effort to only show the notification if the admin is actually changing + // something. this is subject to race conditions with settings changes, but those are + // unlikely to realistically interfere + if (wasLocationEnabled != locationEnabled) { + showLocationSettingsChangedNotification(user); + } + }); DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_SECURE_SETTING) @@ -11575,6 +11594,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .write(); } + private void showLocationSettingsChangedNotification(UserHandle user) { + PendingIntent locationSettingsIntent = mInjector.pendingIntentGetActivityAsUser(mContext, 0, + new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), PendingIntent.FLAG_UPDATE_CURRENT, + null, user); + Notification notification = new Notification.Builder(mContext, + SystemNotificationChannels.DEVICE_ADMIN) + .setSmallIcon(R.drawable.ic_info_outline) + .setContentTitle(mContext.getString(R.string.location_changed_notification_title)) + .setContentText(mContext.getString(R.string.location_changed_notification_text)) + .setColor(mContext.getColor(R.color.system_notification_accent_color)) + .setShowWhen(true) + .setContentIntent(locationSettingsIntent) + .setAutoCancel(true) + .build(); + mInjector.getNotificationManager().notify(SystemMessage.NOTE_LOCATION_CHANGED, + notification); + } + @Override public void requestSetLocationProviderAllowed(ComponentName who, String provider, boolean providerAllowed) { @@ -11645,6 +11683,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { throw new SecurityException(String.format( "Permission denial: Profile owners cannot update %1$s", setting)); } + if (setting.equals(Settings.Secure.LOCATION_MODE) + && isSetSecureSettingLocationModeCheckEnabled(who.getPackageName(), + callingUserId)) { + throw new UnsupportedOperationException(Settings.Secure.LOCATION_MODE + " is " + + "deprecated. Please use setLocationEnabled() instead."); + } if (setting.equals(Settings.Secure.INSTALL_NON_MARKET_APPS)) { if (getTargetSdk(who.getPackageName(), callingUserId) >= Build.VERSION_CODES.O) { throw new UnsupportedOperationException(Settings.Secure.INSTALL_NON_MARKET_APPS @@ -11689,6 +11733,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { saveSettingsLocked(callingUserId); } mInjector.settingsSecurePutStringForUser(setting, value, callingUserId); + if (setting.equals(Settings.Secure.LOCATION_MODE)) { + showLocationSettingsChangedNotification(UserHandle.of(callingUserId)); + } }); } DevicePolicyEventLogger @@ -11698,6 +11745,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .write(); } + private boolean isSetSecureSettingLocationModeCheckEnabled(String packageName, int userId) { + try { + return mIPlatformCompat.isChangeEnabledByPackageName(USE_SET_LOCATION_ENABLED, + packageName, userId); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e); + return getTargetSdk(packageName, userId) > Build.VERSION_CODES.Q; + } + } + @Override public void setMasterVolumeMuted(ComponentName who, boolean on) { Objects.requireNonNull(who, "ComponentName is null"); |