Merge "[Settings] Set different ringtones at work profile"

This commit is contained in:
André Lago
2016-08-19 17:02:02 +00:00
committed by Android (Google) Code Review
5 changed files with 358 additions and 7 deletions

View File

@@ -6048,6 +6048,36 @@
<!-- Do not disturb: Title for the Visual interruptions option and associated settings page. [CHAR LIMIT=30] -->
<string name="zen_mode_visual_interruptions_settings_title">Block visual disturbances</string>
<!-- Work Sounds: Work sound settings section header. [CHAR LIMIT=50] -->
<string name="sound_work_settings">Work profile sounds</string>
<!-- Work Sounds: Title for the switch that enables syncing of personal ringtones to work profile. [CHAR LIMIT=30] -->
<string name="work_use_personal_sounds_title">Use personal profile sounds</string>
<!-- Work Sound: Summary for the switch that enables syncing of personal ringtones to work profile. [CHAR LIMIT=60] -->
<string name="work_use_personal_sounds_summary">Work profile sounds are the same as personal profile</string>
<!-- Work Sounds: Title for the option defining the work phone ringtone. [CHAR LIMIT=30] -->
<string name="work_ringtone_title">Work phone ringtone</string>
<!-- Work Sounds: Title for the option defining the default work notification ringtone. [CHAR LIMIT=30] -->
<string name="work_notification_ringtone_title">Default work notification tone</string>
<!-- Work Sound: Title for the option defining the default work alarm ringtone. [CHAR LIMIT=30] -->
<string name="work_alarm_ringtone_title">Default work alarm ringtone</string>
<!-- Work Sound: Summary for sounds when sync with personal sounds is active [CHAR LIMIT=60] -->
<string name="work_sound_same_as_personal">Same as personal profile</string>
<!-- Work Sound: Title for dialog shown when enabling sync with personal sounds. [CHAR LIMIT=30] -->
<string name="work_sync_dialog_title">Replace work profile sounds?</string>
<!-- Work Sound: Confirm action text for dialog shown when enabling sync with personal sounds. [CHAR LIMIT=30] -->
<string name="work_sync_dialog_yes">Replace</string>
<!-- Work Sound: Message for dialog shown when enabling sync with personal sounds. [CHAR LIMIT=none] -->
<string name="work_sync_dialog_message">Your current work profile sounds will be replaced with your personal profile sounds</string>
<!-- Configure Notifications Settings title. [CHAR LIMIT=30] -->
<string name="configure_notification_settings">Configure notifications</string>

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
android:title="@string/sound_work_settings"
android:key="sound_work_settings">
<PreferenceCategory
android:key="sound_work_settings_section"
android:title="@string/sound_work_settings">
<!-- Use the same sounds of the work profile -->
<SwitchPreference
android:key="work_use_personal_sounds"
android:title="@string/work_use_personal_sounds_title"
android:summary="@string/work_use_personal_sounds_summary"
android:disableDependentsState="true" />
<!-- Work phone ringtone -->
<com.android.settings.DefaultRingtonePreference
android:key="work_ringtone"
android:title="@string/work_ringtone_title"
android:dialogTitle="@string/work_alarm_ringtone_title"
android:ringtoneType="ringtone"
android:dependency="work_use_personal_sounds" />
<!-- Default work notification ringtone -->
<com.android.settings.DefaultRingtonePreference
android:key="work_notification_ringtone"
android:title="@string/work_notification_ringtone_title"
android:dialogTitle="@string/work_alarm_ringtone_title"
android:ringtoneType="notification"
android:dependency="work_use_personal_sounds" />
<!-- Default work alarm ringtone -->
<com.android.settings.DefaultRingtonePreference
android:key="work_alarm_ringtone"
android:title="@string/work_alarm_ringtone_title"
android:dialogTitle="@string/work_alarm_ringtone_title"
android:persistent="false"
android:ringtoneType="alarm"
android:dependency="work_use_personal_sounds" />
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -19,36 +19,66 @@ package com.android.settings;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.RingtoneManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
public class DefaultRingtonePreference extends RingtonePreference {
private static final String TAG = "DefaultRingtonePreference";
private int mUserId;
private Context mUserContext;
public DefaultRingtonePreference(Context context, AttributeSet attrs) {
super(context, attrs);
mUserContext = getContext();
}
public void setUserId(int userId) {
mUserId = userId;
Context context = getContext();
mUserContext = Utils.createPackageContextAsUser(context, mUserId);
}
@Override
public void performClick() {
if (!Utils.startQuietModeDialogIfNecessary(getContext(), UserManager.get(getContext()),
mUserId)) {
super.performClick();
}
}
public void clearUserId(int userId) {
mUserId = UserHandle.USER_CURRENT;
mUserContext = getContext();
}
@Override
public void onPrepareRingtonePickerIntent(Intent ringtonePickerIntent) {
super.onPrepareRingtonePickerIntent(ringtonePickerIntent);
/*
* Since this preference is for choosing the default ringtone, it
* doesn't make sense to show a 'Default' item.
*/
ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, false);
if (mUserId != UserHandle.USER_CURRENT) {
ringtonePickerIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
}
}
@Override
protected void onSaveRingtone(Uri ringtoneUri) {
RingtoneManager.setActualDefaultRingtoneUri(getContext(), getRingtoneType(), ringtoneUri);
RingtoneManager.setActualDefaultRingtoneUri(mUserContext, getRingtoneType(), ringtoneUri);
}
@Override
protected Uri onRestoreRingtone() {
return RingtoneManager.getActualDefaultRingtoneUri(getContext(), getRingtoneType());
return RingtoneManager.getActualDefaultRingtoneUri(mUserContext, getRingtoneType());
}
}

View File

@@ -1160,4 +1160,17 @@ public final class Utils extends com.android.settingslib.Utils {
}
return false;
}
/**
* Returns a context created from the given context for the given user, or null if it fails
*/
public static Context createPackageContextAsUser(Context context, int userId) {
try {
return context.createPackageContextAsUser(
context.getPackageName(), 0 /* flags */, UserHandle.of(userId));
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Failed to create user context", e);
}
return null;
}
}

View File

@@ -16,21 +16,30 @@
package com.android.settings.notification;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.AsyncTask;
@@ -47,7 +56,9 @@ import android.provider.OpenableColumns;
import android.provider.SearchIndexableResource;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.TwoStatePreference;
import android.text.TextUtils;
import android.util.Log;
@@ -55,6 +66,7 @@ import android.util.Log;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.RingtonePreference;
import com.android.settings.DefaultRingtonePreference;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.dashboard.SummaryLoader;
@@ -69,9 +81,11 @@ import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import static android.content.ContentProvider.getUriWithoutUserId;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
public class SoundSettings extends SettingsPreferenceFragment implements Indexable {
public class SoundSettings extends SettingsPreferenceFragment
implements Indexable, OnPreferenceChangeListener {
private static final String TAG = "SoundSettings";
private static final String KEY_MEDIA_VOLUME = "media_volume";
@@ -86,6 +100,12 @@ public class SoundSettings extends SettingsPreferenceFragment implements Indexab
private static final String KEY_ZEN_MODE = "zen_mode";
private static final String KEY_CELL_BROADCAST_SETTINGS = "cell_broadcast_settings";
private static final String KEY_WORK_CATEGORY = "sound_work_settings_section";
private static final String KEY_WORK_USE_PERSONAL_SOUNDS = "work_use_personal_sounds";
private static final String KEY_WORK_PHONE_RINGTONE = "work_ringtone";
private static final String KEY_WORK_NOTIFICATION_RINGTONE = "work_notification_ringtone";
private static final String KEY_WORK_ALARM_RINGTONE = "work_alarm_ringtone";
private static final String SELECTED_PREFERENCE_KEY = "selected_preference";
private static final int REQUEST_CODE = 200;
@@ -118,10 +138,18 @@ public class SoundSettings extends SettingsPreferenceFragment implements Indexab
private ComponentName mSuppressor;
private int mRingerMode = -1;
private PreferenceGroup mWorkPreferenceCategory;
private TwoStatePreference mWorkUsePersonalSounds;
private DefaultRingtonePreference mWorkPhoneRingtonePreference;
private DefaultRingtonePreference mWorkNotificationRingtonePreference;
private DefaultRingtonePreference mWorkAlarmRingtonePreference;
private PackageManager mPm;
private UserManager mUserManager;
private RingtonePreference mRequestPreference;
private @UserIdInt int mManagedProfileId;
@Override
public int getMetricsCategory() {
return MetricsEvent.SOUND;
@@ -227,6 +255,20 @@ public class SoundSettings extends SettingsPreferenceFragment implements Indexab
broadcastSettingsPref.checkRestrictionAndSetDisabled(
UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
}
mManagedProfileId = Utils.getManagedProfileId(mUserManager, UserHandle.myUserId());
if (hasManagedProfile()) {
if ((mWorkPreferenceCategory == null)) {
// Work preferences not yet set
addPreferencesFromResource(R.xml.sound_work_settings);
initWorkPreferences();
}
if (!mWorkUsePersonalSounds.isChecked()) {
updateWorkRingtoneSummaries();
}
} else {
maybeRemoveWorkPreferences();
}
}
@Override
@@ -267,6 +309,34 @@ public class SoundSettings extends SettingsPreferenceFragment implements Indexab
}
}
/**
* Updates the summary of work preferences
*
* This fragment only listens to changes on the work ringtone preferences, identified by keys
* "work_ringtone", "work_notification_ringtone" and "work_alarm_ringtone".
*
* Note: Changes to the personal ringtones aren't listened to this way because they were already
* handled using a {@link #SettingsObserver} ContentObserver. This wouldn't be appropriate for
* work settings since the Settings app runs on the personal user.
*/
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
int ringtoneType;
if (KEY_WORK_PHONE_RINGTONE.equals(preference.getKey())) {
ringtoneType = RingtoneManager.TYPE_RINGTONE;
} else if (KEY_WORK_NOTIFICATION_RINGTONE.equals(preference.getKey())) {
ringtoneType = RingtoneManager.TYPE_NOTIFICATION;
} else if (KEY_WORK_ALARM_RINGTONE.equals(preference.getKey())) {
ringtoneType = RingtoneManager.TYPE_ALARM;
} else {
return true;
}
Context managedProfileContext = Utils.createPackageContextAsUser(mContext, mManagedProfileId);
preference.setSummary(updateRingtoneName(managedProfileContext, ringtoneType));
return true;
}
// === Volumes ===
private VolumeSeekBarPreference initVolumePreference(String key, int stream, int muteIcon) {
@@ -415,7 +485,7 @@ public class SoundSettings extends SettingsPreferenceFragment implements Indexab
} else {
Cursor cursor = null;
try {
if (MediaStore.AUTHORITY.equals(ringtoneUri.getAuthority())) {
if (MediaStore.AUTHORITY.equals(getUriWithoutUserId(ringtoneUri).getAuthority())) {
// Fetch the ringtone title from the media provider
cursor = context.getContentResolver().query(ringtoneUri,
new String[] { MediaStore.Audio.Media.TITLE }, null, null, null);
@@ -663,4 +733,152 @@ public class SoundSettings extends SettingsPreferenceFragment implements Indexab
return rt;
}
};
// === Work Sound Settings ===
private boolean hasManagedProfile() {
return mManagedProfileId != UserHandle.USER_NULL;
}
private void initWorkPreferences() {
mWorkPreferenceCategory =
(PreferenceGroup) getPreferenceScreen().findPreference(KEY_WORK_CATEGORY);
mWorkUsePersonalSounds = (TwoStatePreference) getPreferenceScreen()
.findPreference(KEY_WORK_USE_PERSONAL_SOUNDS);
mWorkPhoneRingtonePreference = (DefaultRingtonePreference) getPreferenceScreen()
.findPreference(KEY_WORK_PHONE_RINGTONE);
mWorkNotificationRingtonePreference = (DefaultRingtonePreference) getPreferenceScreen()
.findPreference(KEY_WORK_NOTIFICATION_RINGTONE);
mWorkAlarmRingtonePreference = (DefaultRingtonePreference) getPreferenceScreen()
.findPreference(KEY_WORK_ALARM_RINGTONE);
// Required so that RingtonePickerActivity lists the work profile ringtones
mWorkPhoneRingtonePreference.setUserId(mManagedProfileId);
mWorkNotificationRingtonePreference.setUserId(mManagedProfileId);
mWorkAlarmRingtonePreference.setUserId(mManagedProfileId);
mWorkPhoneRingtonePreference.setOnPreferenceChangeListener(this);
mWorkNotificationRingtonePreference.setOnPreferenceChangeListener(this);
mWorkAlarmRingtonePreference.setOnPreferenceChangeListener(this);
Context managedProfileContext = Utils.createPackageContextAsUser(mContext, mManagedProfileId);
if (Settings.Secure.getIntForUser(managedProfileContext.getContentResolver(),
Settings.Secure.SYNC_PARENT_SOUNDS, 0, mManagedProfileId) == 1) {
enableWorkSyncSettings();
} else {
disableWorkSyncSettings();
}
mWorkUsePersonalSounds.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if ((boolean) newValue) {
UnifyWorkDialogFragment.show(SoundSettings.this);
return false;
} else {
disableWorkSync();
return true;
}
}
});
}
private void enableWorkSync() {
if(hasManagedProfile()) {
Context managedProfileContext = Utils.createPackageContextAsUser(mContext, mManagedProfileId);
RingtoneManager.enableSyncFromParent(managedProfileContext);
enableWorkSyncSettings();
}
}
private void enableWorkSyncSettings() {
mWorkUsePersonalSounds.setChecked(true);
mWorkPhoneRingtonePreference.setSummary(R.string.work_sound_same_as_personal);
mWorkNotificationRingtonePreference.setSummary(R.string.work_sound_same_as_personal);
mWorkAlarmRingtonePreference.setSummary(R.string.work_sound_same_as_personal);
}
private void disableWorkSync() {
if(hasManagedProfile()) {
Context managedProfileContext = Utils.createPackageContextAsUser(mContext, mManagedProfileId);
RingtoneManager.disableSyncFromParent(managedProfileContext);
disableWorkSyncSettings();
}
}
private void disableWorkSyncSettings() {
mWorkPhoneRingtonePreference.setEnabled(true);
mWorkNotificationRingtonePreference.setEnabled(true);
mWorkAlarmRingtonePreference.setEnabled(true);
updateWorkRingtoneSummaries();
}
private void updateWorkRingtoneSummaries() {
Context managedProfileContext = Utils.createPackageContextAsUser(mContext, mManagedProfileId);
mWorkPhoneRingtonePreference.setSummary(
updateRingtoneName(managedProfileContext, RingtoneManager.TYPE_RINGTONE));
mWorkNotificationRingtonePreference.setSummary(
updateRingtoneName(managedProfileContext, RingtoneManager.TYPE_NOTIFICATION));
mWorkAlarmRingtonePreference.setSummary(
updateRingtoneName(managedProfileContext, RingtoneManager.TYPE_ALARM));
}
private Context createPackageContextAsUser(int userId) {
try {
return mContext.createPackageContextAsUser(
mContext.getPackageName(), 0 /* flags */, UserHandle.of(userId));
} catch (PackageManager.NameNotFoundException e) {
// Should never happen
Log.e(TAG, "Failed to create managed user context", e);
}
return null;
}
private void maybeRemoveWorkPreferences() {
if (mWorkPreferenceCategory == null) {
// No work preferences to remove
return;
}
getPreferenceScreen().removePreference(mWorkPreferenceCategory);
mWorkPreferenceCategory = null;
mWorkPhoneRingtonePreference = null;
mWorkNotificationRingtonePreference = null;
mWorkAlarmRingtonePreference = null;
}
public static class UnifyWorkDialogFragment extends DialogFragment
implements DialogInterface.OnClickListener {
private static final String TAG = "UnifyWorkDialogFragment";
private static final int REQUEST_CODE = 200;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.work_sync_dialog_title)
.setMessage(R.string.work_sync_dialog_message)
.setPositiveButton(R.string.work_sync_dialog_yes, UnifyWorkDialogFragment.this)
.setNegativeButton(android.R.string.no, null)
.create();
}
public static void show(SoundSettings parent) {
FragmentManager fm = parent.getFragmentManager();
if (fm.findFragmentByTag(TAG) == null) {
UnifyWorkDialogFragment fragment = new UnifyWorkDialogFragment();
fragment.setTargetFragment(parent, REQUEST_CODE);
fragment.show(fm, TAG);
}
}
@Override
public void onClick(DialogInterface dialog, int which) {
SoundSettings soundSettings = (SoundSettings) getTargetFragment();
if (soundSettings.isAdded()) {
soundSettings.enableWorkSync();
}
}
}
}