Return masked location mode for managed profiles

If there's a user restriction on location sharing in a
managed profile, always return empty string for location
providers so that location can be disabled by the admin
even if the primary user has location enabled.

Also fix an incorrect update of the cache. Shouldn't update
the primary user's cache when the caller is the managed profile.

Bug: 17478855
Change-Id: Icab3459ae351c5cfc287e21df6a5ba1df9dfbdb4
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 30ccd2c..ba5d11d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -56,6 +56,7 @@
 import android.os.UserManager;
 import android.provider.MediaStore;
 import android.provider.Settings;
+import android.provider.Settings.Secure;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.LruCache;
@@ -689,19 +690,30 @@
         // Get methods
         if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) {
             if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser);
-            if (isManagedProfile(callingUser) && sSystemCloneToManagedKeys.contains(request)) {
-                callingUser = UserHandle.USER_OWNER;
+            // Check if this request should be (re)directed to the primary user's db
+            if (callingUser == UserHandle.USER_OWNER
+                    || shouldShadowParentProfile(callingUser, sSystemCloneToManagedKeys, request)) {
+                dbHelper = getOrEstablishDatabase(UserHandle.USER_OWNER);
+            } else {
+                dbHelper = getOrEstablishDatabase(callingUser);
             }
-            dbHelper = getOrEstablishDatabase(callingUser);
             cache = sSystemCaches.get(callingUser);
             return lookupValue(dbHelper, TABLE_SYSTEM, cache, request);
         }
         if (Settings.CALL_METHOD_GET_SECURE.equals(method)) {
             if (LOCAL_LOGV) Slog.v(TAG, "call(secure:" + request + ") for " + callingUser);
-            if (isManagedProfile(callingUser) && sSecureCloneToManagedKeys.contains(request)) {
-                callingUser = UserHandle.USER_OWNER;
+            // Check if this is a setting to be copied from the primary user
+            if (shouldShadowParentProfile(callingUser, sSecureCloneToManagedKeys, request)) {
+                // If the request if for location providers and there's a restriction, return none
+                if (Secure.LOCATION_PROVIDERS_ALLOWED.equals(request)
+                        && mUserManager.hasUserRestriction(
+                                UserManager.DISALLOW_SHARE_LOCATION, new UserHandle(callingUser))) {
+                    return sSecureCaches.get(callingUser).putIfAbsent(request, "");
+                }
+                dbHelper = getOrEstablishDatabase(UserHandle.USER_OWNER);
+            } else {
+                dbHelper = getOrEstablishDatabase(callingUser);
             }
-            dbHelper = getOrEstablishDatabase(callingUser);
             cache = sSecureCaches.get(callingUser);
             return lookupValue(dbHelper, TABLE_SECURE, cache, request);
         }
@@ -742,11 +754,10 @@
                         + callingUser);
             }
             // Extra check for USER_OWNER to optimize for the 99%
-            if (callingUser != UserHandle.USER_OWNER && isManagedProfile(callingUser)) {
-                if (sSystemCloneToManagedKeys.contains(request)) {
-                    // Don't write these settings
-                    return null;
-                }
+            if (callingUser != UserHandle.USER_OWNER && shouldShadowParentProfile(callingUser,
+                    sSystemCloneToManagedKeys, request)) {
+                // Don't write these settings, as they are cloned from the parent profile
+                return null;
             }
             insertForUser(Settings.System.CONTENT_URI, values, callingUser);
             // Clone the settings to the managed profiles so that notifications can be sent out
@@ -772,11 +783,10 @@
                         + callingUser);
             }
             // Extra check for USER_OWNER to optimize for the 99%
-            if (callingUser != UserHandle.USER_OWNER && isManagedProfile(callingUser)) {
-                if (sSecureCloneToManagedKeys.contains(request)) {
-                    // Don't write these settings
-                    return null;
-                }
+            if (callingUser != UserHandle.USER_OWNER && shouldShadowParentProfile(callingUser,
+                    sSecureCloneToManagedKeys, request)) {
+                // Don't write these settings, as they are cloned from the parent profile
+                return null;
             }
             insertForUser(Settings.Secure.CONTENT_URI, values, callingUser);
             // Clone the settings to the managed profiles so that notifications can be sent out
@@ -816,6 +826,14 @@
         return null;
     }
 
+    /**
+     * Check if the user is a managed profile and name is one of the settings to be cloned
+     * from the parent profile.
+     */
+    private boolean shouldShadowParentProfile(int userId, HashSet<String> keys, String name) {
+        return isManagedProfile(userId) && keys.contains(name);
+    }
+
     // Looks up value 'key' in 'table' and returns either a single-pair Bundle,
     // possibly with a null value, or null on failure.
     private Bundle lookupValue(DatabaseHelper dbHelper, String table,