OSDN Git Service

[Settings] Set different ringtones at work profile
authorAndre Lago <andrelago@google.com>
Mon, 25 Jul 2016 13:12:28 +0000 (14:12 +0100)
committerAndre Lago <andrelago@google.com>
Mon, 15 Aug 2016 10:11:56 +0000 (11:11 +0100)
Updated the Settings app to allow setting different default system
ringtones for work profile apps

Bug: 30658854
Change-Id: I7461be070bd4e8d86bf1fd724039e53d500094ad

res/values/strings.xml
res/xml/sound_work_settings.xml [new file with mode: 0644]
src/com/android/settings/DefaultRingtonePreference.java
src/com/android/settings/Utils.java
src/com/android/settings/notification/SoundSettings.java

index b4abee7..8d53cf4 100644 (file)
     <!--  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>
diff --git a/res/xml/sound_work_settings.xml b/res/xml/sound_work_settings.xml
new file mode 100644 (file)
index 0000000..b63ec75
--- /dev/null
@@ -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>
index 4e0e1e7..9feee13 100644 (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());
     }
-    
+
 }
index 0725386..bbf9823 100644 (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;
+    }
 }
index f06cf41..75365cf 100644 (file)
 
 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
     protected 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();
+            }
+        }
+    }
 }