• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.notification;
18 
19 import android.annotation.UserIdInt;
20 import android.app.AlertDialog;
21 import android.app.Dialog;
22 import android.app.FragmentManager;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.media.Ringtone;
29 import android.media.RingtoneManager;
30 import android.net.Uri;
31 import android.os.Bundle;
32 import android.os.UserHandle;
33 import android.os.UserManager;
34 import android.provider.Settings;
35 import android.support.v7.preference.Preference;
36 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
37 import android.support.v7.preference.PreferenceGroup;
38 import android.support.v7.preference.PreferenceScreen;
39 import android.support.v7.preference.TwoStatePreference;
40 
41 import com.android.internal.annotations.VisibleForTesting;
42 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
43 import com.android.settings.DefaultRingtonePreference;
44 import com.android.settings.R;
45 import com.android.settings.Utils;
46 import com.android.settings.core.PreferenceControllerMixin;
47 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
48 import com.android.settingslib.core.AbstractPreferenceController;
49 import com.android.settingslib.core.lifecycle.Lifecycle;
50 import com.android.settingslib.core.lifecycle.LifecycleObserver;
51 import com.android.settingslib.core.lifecycle.events.OnPause;
52 import com.android.settingslib.core.lifecycle.events.OnResume;
53 
54 public class WorkSoundPreferenceController extends AbstractPreferenceController
55         implements PreferenceControllerMixin, OnPreferenceChangeListener, LifecycleObserver,
56         OnResume, OnPause {
57 
58     private static final String TAG = "WorkSoundPrefController";
59     private static final String KEY_WORK_CATEGORY = "sound_work_settings_section";
60     private static final String KEY_WORK_USE_PERSONAL_SOUNDS = "work_use_personal_sounds";
61     private static final String KEY_WORK_PHONE_RINGTONE = "work_ringtone";
62     private static final String KEY_WORK_NOTIFICATION_RINGTONE = "work_notification_ringtone";
63     private static final String KEY_WORK_ALARM_RINGTONE = "work_alarm_ringtone";
64 
65     private final boolean mVoiceCapable;
66     private final UserManager mUserManager;
67     private final SoundSettings mParent;
68     private final AudioHelper mHelper;
69 
70     private PreferenceGroup mWorkPreferenceCategory;
71     private TwoStatePreference mWorkUsePersonalSounds;
72     private Preference mWorkPhoneRingtonePreference;
73     private Preference mWorkNotificationRingtonePreference;
74     private Preference mWorkAlarmRingtonePreference;
75 
76     @UserIdInt
77     private int mManagedProfileId;
78 
WorkSoundPreferenceController(Context context, SoundSettings parent, Lifecycle lifecycle)79     public WorkSoundPreferenceController(Context context, SoundSettings parent,
80             Lifecycle lifecycle) {
81         this(context, parent, lifecycle, new AudioHelper(context));
82     }
83 
84     @VisibleForTesting
WorkSoundPreferenceController(Context context, SoundSettings parent, Lifecycle lifecycle, AudioHelper helper)85     WorkSoundPreferenceController(Context context, SoundSettings parent, Lifecycle lifecycle,
86             AudioHelper helper) {
87         super(context);
88         mUserManager = UserManager.get(context);
89         mVoiceCapable = Utils.isVoiceCapable(mContext);
90         mParent = parent;
91         mHelper = helper;
92         if (lifecycle != null) {
93             lifecycle.addObserver(this);
94         }
95     }
96 
97     @Override
displayPreference(PreferenceScreen screen)98     public void displayPreference(PreferenceScreen screen) {
99         mWorkPreferenceCategory = (PreferenceGroup) screen.findPreference(KEY_WORK_CATEGORY);
100         if (mWorkPreferenceCategory != null) {
101             mWorkPreferenceCategory.setVisible(isAvailable());
102         }
103     }
104 
105     @Override
onResume()106     public void onResume() {
107         IntentFilter managedProfileFilter = new IntentFilter();
108         managedProfileFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
109         managedProfileFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
110         mContext.registerReceiver(mManagedProfileReceiver, managedProfileFilter);
111 
112         mManagedProfileId = mHelper.getManagedProfileId(mUserManager);
113         updateWorkPreferences();
114     }
115 
116     @Override
onPause()117     public void onPause() {
118         mContext.unregisterReceiver(mManagedProfileReceiver);
119     }
120 
121     @Override
getPreferenceKey()122     public String getPreferenceKey() {
123         return KEY_WORK_CATEGORY;
124     }
125 
126     @Override
isAvailable()127     public boolean isAvailable() {
128         return mHelper.getManagedProfileId(mUserManager) != UserHandle.USER_NULL
129                 && shouldShowRingtoneSettings();
130     }
131 
132     @Override
handlePreferenceTreeClick(Preference preference)133     public boolean handlePreferenceTreeClick(Preference preference) {
134         return false;
135     }
136 
137     /**
138      * Updates the summary of work preferences
139      *
140      * This controller listens to changes on the work ringtone preferences, identified by keys
141      * "work_ringtone", "work_notification_ringtone" and "work_alarm_ringtone".
142      */
143     @Override
onPreferenceChange(Preference preference, Object newValue)144     public boolean onPreferenceChange(Preference preference, Object newValue) {
145         int ringtoneType;
146         if (KEY_WORK_PHONE_RINGTONE.equals(preference.getKey())) {
147             ringtoneType = RingtoneManager.TYPE_RINGTONE;
148         } else if (KEY_WORK_NOTIFICATION_RINGTONE.equals(preference.getKey())) {
149             ringtoneType = RingtoneManager.TYPE_NOTIFICATION;
150         } else if (KEY_WORK_ALARM_RINGTONE.equals(preference.getKey())) {
151             ringtoneType = RingtoneManager.TYPE_ALARM;
152         } else {
153             return true;
154         }
155 
156         preference.setSummary(updateRingtoneName(getManagedProfileContext(), ringtoneType));
157         return true;
158     }
159 
160     // === Phone & notification ringtone ===
161 
shouldShowRingtoneSettings()162     private boolean shouldShowRingtoneSettings() {
163         return !mHelper.isSingleVolume();
164     }
165 
updateRingtoneName(Context context, int type)166     private CharSequence updateRingtoneName(Context context, int type) {
167         if (context == null || !mHelper.isUserUnlocked(mUserManager, context.getUserId())) {
168             return mContext.getString(R.string.managed_profile_not_available_label);
169         }
170         Uri ringtoneUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
171         return Ringtone.getTitle(context, ringtoneUri, false /* followSettingsUri */,
172                 true /* allowRemote */);
173     }
174 
getManagedProfileContext()175     private Context getManagedProfileContext() {
176         if (mManagedProfileId == UserHandle.USER_NULL) {
177             return null;
178         }
179         return mHelper.createPackageContextAsUser(mManagedProfileId);
180     }
181 
initWorkPreference(PreferenceGroup root, String key)182     private DefaultRingtonePreference initWorkPreference(PreferenceGroup root, String key) {
183         DefaultRingtonePreference pref =
184                 (DefaultRingtonePreference) root.findPreference(key);
185         pref.setOnPreferenceChangeListener(this);
186 
187         // Required so that RingtonePickerActivity lists the work profile ringtones
188         pref.setUserId(mManagedProfileId);
189         return pref;
190     }
191 
updateWorkPreferences()192     private void updateWorkPreferences() {
193         if (mWorkPreferenceCategory == null) {
194             return;
195         }
196         final boolean isAvailable = isAvailable();
197         mWorkPreferenceCategory.setVisible(isAvailable);
198         if (!isAvailable) {
199             return;
200         }
201         if (mWorkUsePersonalSounds == null) {
202             mWorkUsePersonalSounds = (TwoStatePreference)
203                     mWorkPreferenceCategory.findPreference(KEY_WORK_USE_PERSONAL_SOUNDS);
204             mWorkUsePersonalSounds.setOnPreferenceChangeListener((Preference p, Object value) -> {
205                 if ((boolean) value) {
206                     UnifyWorkDialogFragment.show(mParent);
207                     return false;
208                 } else {
209                     disableWorkSync();
210                     return true;
211                 }
212             });
213         }
214         if (mWorkPhoneRingtonePreference == null) {
215             mWorkPhoneRingtonePreference = initWorkPreference(mWorkPreferenceCategory,
216                     KEY_WORK_PHONE_RINGTONE);
217         }
218         if (mWorkNotificationRingtonePreference == null) {
219             mWorkNotificationRingtonePreference = initWorkPreference(mWorkPreferenceCategory,
220                     KEY_WORK_NOTIFICATION_RINGTONE);
221         }
222         if (mWorkAlarmRingtonePreference == null) {
223             mWorkAlarmRingtonePreference = initWorkPreference(mWorkPreferenceCategory,
224                     KEY_WORK_ALARM_RINGTONE);
225         }
226         if (!mVoiceCapable) {
227             mWorkPhoneRingtonePreference.setVisible(false);
228             mWorkPhoneRingtonePreference = null;
229         }
230 
231         final Context managedProfileContext = getManagedProfileContext();
232         if (Settings.Secure.getIntForUser(managedProfileContext.getContentResolver(),
233                 Settings.Secure.SYNC_PARENT_SOUNDS, 0, mManagedProfileId) == 1) {
234             enableWorkSyncSettings();
235         } else {
236             disableWorkSyncSettings();
237         }
238     }
239 
enableWorkSync()240     void enableWorkSync() {
241         RingtoneManager.enableSyncFromParent(getManagedProfileContext());
242         enableWorkSyncSettings();
243     }
244 
enableWorkSyncSettings()245     private void enableWorkSyncSettings() {
246         mWorkUsePersonalSounds.setChecked(true);
247 
248         if (mWorkPhoneRingtonePreference != null) {
249             mWorkPhoneRingtonePreference.setSummary(R.string.work_sound_same_as_personal);
250         }
251         mWorkNotificationRingtonePreference.setSummary(R.string.work_sound_same_as_personal);
252         mWorkAlarmRingtonePreference.setSummary(R.string.work_sound_same_as_personal);
253     }
254 
disableWorkSync()255     private void disableWorkSync() {
256         RingtoneManager.disableSyncFromParent(getManagedProfileContext());
257         disableWorkSyncSettings();
258     }
259 
disableWorkSyncSettings()260     private void disableWorkSyncSettings() {
261         if (mWorkPhoneRingtonePreference != null) {
262             mWorkPhoneRingtonePreference.setEnabled(true);
263         }
264         mWorkNotificationRingtonePreference.setEnabled(true);
265         mWorkAlarmRingtonePreference.setEnabled(true);
266 
267         updateWorkRingtoneSummaries();
268     }
269 
updateWorkRingtoneSummaries()270     private void updateWorkRingtoneSummaries() {
271         Context managedProfileContext = getManagedProfileContext();
272 
273         if (mWorkPhoneRingtonePreference != null) {
274             mWorkPhoneRingtonePreference.setSummary(
275                     updateRingtoneName(managedProfileContext, RingtoneManager.TYPE_RINGTONE));
276         }
277         mWorkNotificationRingtonePreference.setSummary(
278                 updateRingtoneName(managedProfileContext, RingtoneManager.TYPE_NOTIFICATION));
279         mWorkAlarmRingtonePreference.setSummary(
280                 updateRingtoneName(managedProfileContext, RingtoneManager.TYPE_ALARM));
281     }
282 
onManagedProfileAdded(@serIdInt int profileId)283     public void onManagedProfileAdded(@UserIdInt int profileId) {
284         if (mManagedProfileId == UserHandle.USER_NULL) {
285             mManagedProfileId = profileId;
286             updateWorkPreferences();
287         }
288     }
289 
onManagedProfileRemoved(@serIdInt int profileId)290     public void onManagedProfileRemoved(@UserIdInt int profileId) {
291         if (mManagedProfileId == profileId) {
292             mManagedProfileId = mHelper.getManagedProfileId(mUserManager);
293             updateWorkPreferences();
294         }
295     }
296 
297     private final BroadcastReceiver mManagedProfileReceiver = new BroadcastReceiver() {
298         @Override
299         public void onReceive(Context context, Intent intent) {
300             final int userId = ((UserHandle) intent.getExtra(Intent.EXTRA_USER)).getIdentifier();
301             switch (intent.getAction()) {
302                 case Intent.ACTION_MANAGED_PROFILE_ADDED: {
303                     onManagedProfileAdded(userId);
304                     return;
305                 }
306                 case Intent.ACTION_MANAGED_PROFILE_REMOVED: {
307                     onManagedProfileRemoved(userId);
308                     return;
309                 }
310             }
311         }
312     };
313 
314     public static class UnifyWorkDialogFragment extends InstrumentedDialogFragment
315             implements DialogInterface.OnClickListener {
316         private static final String TAG = "UnifyWorkDialogFragment";
317         private static final int REQUEST_CODE = 200;
318 
319         @Override
getMetricsCategory()320         public int getMetricsCategory() {
321             return MetricsEvent.DIALOG_UNIFY_SOUND_SETTINGS;
322         }
323 
324         @Override
onCreateDialog(Bundle savedInstanceState)325         public Dialog onCreateDialog(Bundle savedInstanceState) {
326             return new AlertDialog.Builder(getActivity())
327                     .setTitle(R.string.work_sync_dialog_title)
328                     .setMessage(R.string.work_sync_dialog_message)
329                     .setPositiveButton(R.string.work_sync_dialog_yes, UnifyWorkDialogFragment.this)
330                     .setNegativeButton(android.R.string.no, null)
331                     .create();
332         }
333 
show(SoundSettings parent)334         public static void show(SoundSettings parent) {
335             FragmentManager fm = parent.getFragmentManager();
336             if (fm.findFragmentByTag(TAG) == null) {
337                 UnifyWorkDialogFragment fragment = new UnifyWorkDialogFragment();
338                 fragment.setTargetFragment(parent, REQUEST_CODE);
339                 fragment.show(fm, TAG);
340             }
341         }
342 
343         @Override
onClick(DialogInterface dialog, int which)344         public void onClick(DialogInterface dialog, int which) {
345             SoundSettings soundSettings = (SoundSettings) getTargetFragment();
346             if (soundSettings.isAdded()) {
347                 soundSettings.enableWorkSync();
348             }
349         }
350     }
351 
352 }
353