diff options
| author | 2016-08-19 17:02:02 +0000 | |
|---|---|---|
| committer | 2016-08-19 17:02:05 +0000 | |
| commit | 13a5df3b31fd730384480af286d4d4abe84d82f6 (patch) | |
| tree | aea645b87bffc3a4d047050b2c4736016558fa6e | |
| parent | 83c9496cbaef1bf58aefbbf27a40e5ffe41be397 (diff) | |
| parent | 3fa139c7b2fc638424955d0bb07d692f576cccb5 (diff) | |
Merge changes from topic 'Different sound settings for work profile'
* changes:
[media] Separate ringtones for managed profiles
[Settings] Added setting SYNC_PARENT_SOUNDS
| -rwxr-xr-x | core/java/android/provider/Settings.java | 34 | ||||
| -rw-r--r-- | media/java/android/media/MediaPlayer.java | 2 | ||||
| -rw-r--r-- | media/java/android/media/Ringtone.java | 5 | ||||
| -rw-r--r-- | media/java/android/media/RingtoneManager.java | 84 | ||||
| -rw-r--r-- | packages/SettingsProvider/res/values/defaults.xml | 3 | ||||
| -rw-r--r-- | packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java | 47 |
6 files changed, 161 insertions, 14 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index bff4d7dad888..2c02cfa5b7ff 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3817,6 +3817,26 @@ public final class Settings { } /** + * These entries should be cloned from this profile's parent only if the dependency's + * value is true ("1") + * + * Note: the dependencies must be Secure settings + * + * @hide + */ + public static final Map<String, String> CLONE_FROM_PARENT_ON_VALUE = new ArrayMap<>(); + static { + CLONE_FROM_PARENT_ON_VALUE.put(RINGTONE, Secure.SYNC_PARENT_SOUNDS); + CLONE_FROM_PARENT_ON_VALUE.put(NOTIFICATION_SOUND, Secure.SYNC_PARENT_SOUNDS); + CLONE_FROM_PARENT_ON_VALUE.put(ALARM_ALERT, Secure.SYNC_PARENT_SOUNDS); + } + + /** @hide */ + public static void getCloneFromParentOnValueSettings(Map<String, String> outMap) { + outMap.putAll(CLONE_FROM_PARENT_ON_VALUE); + } + + /** * When to use Wi-Fi calling * * @see android.telephony.TelephonyManager.WifiCallingChoices @@ -6061,6 +6081,17 @@ public final class Settings { public static final String VOLUME_CONTROLLER_SERVICE_COMPONENT = "volume_controller_service_component"; + /** + * Defines whether managed profile ringtones should be synced from it's parent profile + * <p> + * 0 = ringtones are not synced + * 1 = ringtones are synced from the profile's parent (default) + * <p> + * This value is only used for managed profiles. + * @hide + */ + public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds"; + /** @hide */ public static final String IMMERSIVE_MODE_CONFIRMATIONS = "immersive_mode_confirmations"; @@ -6432,7 +6463,8 @@ public final class Settings { NIGHT_DISPLAY_CUSTOM_START_TIME, NIGHT_DISPLAY_CUSTOM_END_TIME, NIGHT_DISPLAY_AUTO_MODE, - NIGHT_DISPLAY_ACTIVATED + NIGHT_DISPLAY_ACTIVATED, + SYNC_PARENT_SOUNDS }; /** diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 30395b855a8b..dd2679953dab 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -992,7 +992,7 @@ public class MediaPlayer extends PlayerBase // Try cached ringtone first since the actual provider may not be // encryption aware, or it may be stored on CE media storage final int type = RingtoneManager.getDefaultType(uri); - final Uri cacheUri = RingtoneManager.getCacheForType(type); + final Uri cacheUri = RingtoneManager.getCacheForType(type, context.getUserId()); final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, type); if (attemptDataSource(resolver, cacheUri)) { return; diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java index c2bcd930dd29..8935b7290ea4 100644 --- a/media/java/android/media/Ringtone.java +++ b/media/java/android/media/Ringtone.java @@ -16,6 +16,7 @@ package android.media; +import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; @@ -206,11 +207,11 @@ public class Ringtone { public static String getTitle( Context context, Uri uri, boolean followSettingsUri, boolean allowRemote) { ContentResolver res = context.getContentResolver(); - + String title = null; if (uri != null) { - String authority = uri.getAuthority(); + String authority = ContentProvider.getAuthorityWithoutUserId(uri.getAuthority()); if (Settings.AUTHORITY.equals(authority)) { if (followSettingsUri) { diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index 86ebae111029..664765a89a3a 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -16,18 +16,24 @@ package android.media; +import android.Manifest; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.Activity; +import android.content.ContentProvider; import android.content.ContentResolver; import android.content.ContentUris; import android.content.Context; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.database.Cursor; import android.net.Uri; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.UserHandle; +import android.os.UserManager; import android.provider.MediaStore; import android.provider.Settings; import android.provider.Settings.System; @@ -43,6 +49,9 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.List; +import static android.content.ContentProvider.maybeAddUserId; +import static android.content.pm.PackageManager.NameNotFoundException; + /** * RingtoneManager provides access to ringtones, notification, and other types * of sounds. It manages querying the different media providers and combines the @@ -82,6 +91,10 @@ public class RingtoneManager { * All types of sounds. */ public static final int TYPE_ALL = TYPE_RINGTONE | TYPE_NOTIFICATION | TYPE_ALARM; + + private static final int[] RINGTONE_TYPES = { + TYPE_RINGTONE, TYPE_NOTIFICATION, TYPE_ALARM + }; // </attr> @@ -629,6 +642,48 @@ public class RingtoneManager { } /** + * Disables Settings.System.SYNC_PARENT_SOUNDS, copying the parent's ringtones to the current + * profile + * + * @hide + */ + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + public static void disableSyncFromParent(Context userContext) { + // Must disable sync first so that ringtone copy below doesn't get redirected to parent + Settings.Secure.putIntForUser(userContext.getContentResolver(), + Settings.Secure.SYNC_PARENT_SOUNDS, 0 /* false */, userContext.getUserId()); + + // Copy ringtones from parent profile + UserManager um = UserManager.get(userContext); + UserInfo parentInfo = um.getProfileParent(userContext.getUserId()); + if (parentInfo != null) { + try { + Context targetContext = userContext.createPackageContextAsUser( + userContext.getPackageName(), 0 /* flags */, UserHandle.of(parentInfo.id)); + for (int ringtoneType : RINGTONE_TYPES) { + Uri ringtoneUri = getActualDefaultRingtoneUri(targetContext, ringtoneType); + // Add user id of parent so that custom ringtones can be read and played + RingtoneManager.setActualDefaultRingtoneUri(userContext, ringtoneType, + maybeAddUserId(ringtoneUri, parentInfo.id)); + } + } catch (NameNotFoundException e) { + Log.e(TAG, "Unable to create parent context", e); + } + } + } + + /** + * Enables Settings.System.SYNC_PARENT_SOUNDS for the content's user + * + * @hide + */ + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + public static void enableSyncFromParent(Context userContext) { + Settings.Secure.putIntForUser(userContext.getContentResolver(), + Settings.Secure.SYNC_PARENT_SOUNDS, 1 /* true */, userContext.getUserId()); + } + + /** * Gets the current default sound's {@link Uri}. This will give the actual * sound {@link Uri}, instead of using this, most clients can use * {@link System#DEFAULT_RINGTONE_URI}. @@ -645,7 +700,16 @@ public class RingtoneManager { if (setting == null) return null; final String uriString = Settings.System.getStringForUser(context.getContentResolver(), setting, context.getUserId()); - return uriString != null ? Uri.parse(uriString) : null; + Uri ringtoneUri = uriString != null ? Uri.parse(uriString) : null; + + // If this doesn't verify, the user id must be kept in the uri to ensure it resolves in the + // correct user storage + if (ringtoneUri != null + && ContentProvider.getUserIdFromUri(ringtoneUri) == context.getUserId()) { + ringtoneUri = ContentProvider.getUriWithoutUserId(ringtoneUri); + } + + return ringtoneUri; } /** @@ -663,13 +727,14 @@ public class RingtoneManager { String setting = getSettingForType(type); if (setting == null) return; + ringtoneUri = ContentProvider.maybeAddUserId(ringtoneUri, context.getUserId()); Settings.System.putStringForUser(resolver, setting, ringtoneUri != null ? ringtoneUri.toString() : null, context.getUserId()); // Stream selected ringtone into cache so it's available for playback // when CE storage is still locked if (ringtoneUri != null) { - final Uri cacheUri = getCacheForType(type); + final Uri cacheUri = getCacheForType(type, context.getUserId()); try (InputStream in = openRingtone(context, ringtoneUri); OutputStream out = resolver.openOutputStream(cacheUri)) { Streams.copy(in, out); @@ -715,15 +780,20 @@ public class RingtoneManager { /** {@hide} */ public static Uri getCacheForType(int type) { + return getCacheForType(type, UserHandle.getCallingUserId()); + } + + /** {@hide} */ + public static Uri getCacheForType(int type, int userId) { if ((type & TYPE_RINGTONE) != 0) { - return Settings.System.RINGTONE_CACHE_URI; + return ContentProvider.maybeAddUserId(Settings.System.RINGTONE_CACHE_URI, userId); } else if ((type & TYPE_NOTIFICATION) != 0) { - return Settings.System.NOTIFICATION_SOUND_CACHE_URI; + return ContentProvider.maybeAddUserId(Settings.System.NOTIFICATION_SOUND_CACHE_URI, + userId); } else if ((type & TYPE_ALARM) != 0) { - return Settings.System.ALARM_ALERT_CACHE_URI; - } else { - return null; + return ContentProvider.maybeAddUserId(Settings.System.ALARM_ALERT_CACHE_URI, userId); } + return null; } /** diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index fad102f6e6f8..c1e4e2acbe31 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -89,6 +89,9 @@ <!-- Default for Settings.System.VIBRATE_IN_SILENT --> <bool name="def_vibrate_in_silent">true</bool> + <!-- Default for Settings.Secure.SYNC_PARENT_SOUNDS --> + <bool name="def_sync_parent_sounds">true</bool> + <!-- Default for Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION --> <bool name="def_accessibility_script_injection">false</bool> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index ac311ba4009c..37e7442d3e5d 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -58,6 +58,7 @@ import android.os.UserManager; import android.os.UserManagerInternal; import android.provider.Settings; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; @@ -76,6 +77,7 @@ import java.io.PrintWriter; import java.security.SecureRandom; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.regex.Pattern; @@ -195,6 +197,13 @@ public class SettingsProvider extends ContentProvider { Settings.System.getCloneToManagedProfileSettings(sSystemCloneToManagedSettings); } + // Per user system settings that are cloned from the profile's parent when a dependency + // in {@link Settings.Secure} is set to "1". + public static final Map<String, String> sSystemCloneFromParentOnDependency = new ArrayMap<>(); + static { + Settings.System.getCloneFromParentOnValueSettings(sSystemCloneFromParentOnDependency); + } + private final Object mLock = new Object(); @GuardedBy("mLock") @@ -518,19 +527,29 @@ public class SettingsProvider extends ContentProvider { } uri = ContentProvider.getUriWithoutUserId(uri); + final String cacheRingtoneSetting; final String cacheName; if (Settings.System.RINGTONE_CACHE_URI.equals(uri)) { + cacheRingtoneSetting = Settings.System.RINGTONE; cacheName = Settings.System.RINGTONE_CACHE; } else if (Settings.System.NOTIFICATION_SOUND_CACHE_URI.equals(uri)) { + cacheRingtoneSetting = Settings.System.NOTIFICATION_SOUND; cacheName = Settings.System.NOTIFICATION_SOUND_CACHE; } else if (Settings.System.ALARM_ALERT_CACHE_URI.equals(uri)) { + cacheRingtoneSetting = Settings.System.ALARM_ALERT; cacheName = Settings.System.ALARM_ALERT_CACHE; } else { throw new FileNotFoundException("Direct file access no longer supported; " + "ringtone playback is available through android.media.Ringtone"); } - final File cacheFile = new File(getRingtoneCacheDir(userId), cacheName); + int actualCacheOwner; + // Redirect cache to parent if ringtone setting is owned by profile parent + synchronized (mLock) { + actualCacheOwner = resolveOwningUserIdForSystemSettingLocked(userId, + cacheRingtoneSetting); + } + final File cacheFile = new File(getRingtoneCacheDir(actualCacheOwner), cacheName); return ParcelFileDescriptor.open(cacheFile, ParcelFileDescriptor.parseMode(mode)); } @@ -1102,7 +1121,7 @@ public class SettingsProvider extends ContentProvider { } if (cacheName != null) { final File cacheFile = new File( - getRingtoneCacheDir(UserHandle.getCallingUserId()), cacheName); + getRingtoneCacheDir(owningUserId), cacheName); cacheFile.delete(); } @@ -1242,6 +1261,16 @@ public class SettingsProvider extends ContentProvider { } private int resolveOwningUserIdForSystemSettingLocked(int userId, String setting) { + final int parentId; + // Resolves dependency if setting has a dependency and the calling user has a parent + if (sSystemCloneFromParentOnDependency.containsKey(setting) + && (parentId = getGroupParentLocked(userId)) != userId) { + // The setting has a dependency and the profile has a parent + String dependency = sSystemCloneFromParentOnDependency.get(setting); + if (getSecureSetting(dependency, userId).getValue().equals("1")) { + return parentId; + } + } return resolveOwningUserIdLocked(userId, sSystemCloneToManagedSettings, setting); } @@ -2108,7 +2137,7 @@ public class SettingsProvider extends ContentProvider { } private final class UpgradeController { - private static final int SETTINGS_VERSION = 131; + private static final int SETTINGS_VERSION = 132; private final int mUserId; @@ -2432,6 +2461,18 @@ public class SettingsProvider extends ContentProvider { currentVersion = 131; } + if (currentVersion == 131) { + // Version 131: Allow managed profile to optionally use the parent's ringtones + final SettingsState systemSecureSettings = getSecureSettingsLocked(userId); + String defaultSyncParentSounds = (getContext().getResources() + .getBoolean(R.bool.def_sync_parent_sounds) ? "1" : "0"); + systemSecureSettings.insertSettingLocked( + Settings.Secure.SYNC_PARENT_SOUNDS, + defaultSyncParentSounds, + SettingsState.SYSTEM_PACKAGE_NAME); + currentVersion = 132; + } + if (currentVersion != newVersion) { Slog.w("SettingsProvider", "warning: upgrading settings database to version " + newVersion + " left it at " |