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.PreferenceController; 47 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 48 import com.android.settings.core.lifecycle.Lifecycle; 49 import com.android.settings.core.lifecycle.LifecycleObserver; 50 import com.android.settings.core.lifecycle.events.OnPause; 51 import com.android.settings.core.lifecycle.events.OnResume; 52 53 public class WorkSoundPreferenceController extends PreferenceController implements 54 OnPreferenceChangeListener, LifecycleObserver, OnResume, OnPause { 55 56 private static final String TAG = "WorkSoundPrefController"; 57 private static final String KEY_WORK_CATEGORY = "sound_work_settings_section"; 58 private static final String KEY_WORK_USE_PERSONAL_SOUNDS = "work_use_personal_sounds"; 59 private static final String KEY_WORK_PHONE_RINGTONE = "work_ringtone"; 60 private static final String KEY_WORK_NOTIFICATION_RINGTONE = "work_notification_ringtone"; 61 private static final String KEY_WORK_ALARM_RINGTONE = "work_alarm_ringtone"; 62 63 private final boolean mVoiceCapable; 64 private final UserManager mUserManager; 65 private final SoundSettings mParent; 66 private final AudioHelper mHelper; 67 68 private PreferenceGroup mWorkPreferenceCategory; 69 private TwoStatePreference mWorkUsePersonalSounds; 70 private Preference mWorkPhoneRingtonePreference; 71 private Preference mWorkNotificationRingtonePreference; 72 private Preference mWorkAlarmRingtonePreference; 73 74 @UserIdInt 75 private int mManagedProfileId; 76 WorkSoundPreferenceController(Context context, SoundSettings parent, Lifecycle lifecycle)77 public WorkSoundPreferenceController(Context context, SoundSettings parent, 78 Lifecycle lifecycle) { 79 this(context, parent, lifecycle, new AudioHelper(context)); 80 } 81 82 @VisibleForTesting WorkSoundPreferenceController(Context context, SoundSettings parent, Lifecycle lifecycle, AudioHelper helper)83 WorkSoundPreferenceController(Context context, SoundSettings parent, Lifecycle lifecycle, 84 AudioHelper helper) { 85 super(context); 86 mUserManager = UserManager.get(context); 87 mVoiceCapable = Utils.isVoiceCapable(mContext); 88 mParent = parent; 89 mHelper = helper; 90 if (lifecycle != null) { 91 lifecycle.addObserver(this); 92 } 93 } 94 95 @Override displayPreference(PreferenceScreen screen)96 public void displayPreference(PreferenceScreen screen) { 97 mWorkPreferenceCategory = (PreferenceGroup) screen.findPreference(KEY_WORK_CATEGORY); 98 if (mWorkPreferenceCategory != null) { 99 mWorkPreferenceCategory.setVisible(isAvailable()); 100 } 101 } 102 103 @Override onResume()104 public void onResume() { 105 IntentFilter managedProfileFilter = new IntentFilter(); 106 managedProfileFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); 107 managedProfileFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); 108 mContext.registerReceiver(mManagedProfileReceiver, managedProfileFilter); 109 110 mManagedProfileId = mHelper.getManagedProfileId(mUserManager); 111 updateWorkPreferences(); 112 } 113 114 @Override onPause()115 public void onPause() { 116 mContext.unregisterReceiver(mManagedProfileReceiver); 117 } 118 119 @Override getPreferenceKey()120 public String getPreferenceKey() { 121 return KEY_WORK_CATEGORY; 122 } 123 124 @Override isAvailable()125 public boolean isAvailable() { 126 return mHelper.getManagedProfileId(mUserManager) != UserHandle.USER_NULL 127 && shouldShowRingtoneSettings(); 128 } 129 130 @Override handlePreferenceTreeClick(Preference preference)131 public boolean handlePreferenceTreeClick(Preference preference) { 132 return false; 133 } 134 135 /** 136 * Updates the summary of work preferences 137 * 138 * This controller listens to changes on the work ringtone preferences, identified by keys 139 * "work_ringtone", "work_notification_ringtone" and "work_alarm_ringtone". 140 */ 141 @Override onPreferenceChange(Preference preference, Object newValue)142 public boolean onPreferenceChange(Preference preference, Object newValue) { 143 int ringtoneType; 144 if (KEY_WORK_PHONE_RINGTONE.equals(preference.getKey())) { 145 ringtoneType = RingtoneManager.TYPE_RINGTONE; 146 } else if (KEY_WORK_NOTIFICATION_RINGTONE.equals(preference.getKey())) { 147 ringtoneType = RingtoneManager.TYPE_NOTIFICATION; 148 } else if (KEY_WORK_ALARM_RINGTONE.equals(preference.getKey())) { 149 ringtoneType = RingtoneManager.TYPE_ALARM; 150 } else { 151 return true; 152 } 153 154 preference.setSummary(updateRingtoneName(getManagedProfileContext(), ringtoneType)); 155 return true; 156 } 157 158 // === Phone & notification ringtone === 159 shouldShowRingtoneSettings()160 private boolean shouldShowRingtoneSettings() { 161 return !mHelper.isSingleVolume(); 162 } 163 updateRingtoneName(Context context, int type)164 private CharSequence updateRingtoneName(Context context, int type) { 165 if (context == null || !mHelper.isUserUnlocked(mUserManager, context.getUserId())) { 166 return mContext.getString(R.string.managed_profile_not_available_label); 167 } 168 Uri ringtoneUri = RingtoneManager.getActualDefaultRingtoneUri(context, type); 169 return Ringtone.getTitle(context, ringtoneUri, false /* followSettingsUri */, 170 true /* allowRemote */); 171 } 172 getManagedProfileContext()173 private Context getManagedProfileContext() { 174 if (mManagedProfileId == UserHandle.USER_NULL) { 175 return null; 176 } 177 return mHelper.createPackageContextAsUser(mManagedProfileId); 178 } 179 initWorkPreference(PreferenceGroup root, String key)180 private DefaultRingtonePreference initWorkPreference(PreferenceGroup root, String key) { 181 DefaultRingtonePreference pref = 182 (DefaultRingtonePreference) root.findPreference(key); 183 pref.setOnPreferenceChangeListener(this); 184 185 // Required so that RingtonePickerActivity lists the work profile ringtones 186 pref.setUserId(mManagedProfileId); 187 return pref; 188 } 189 updateWorkPreferences()190 private void updateWorkPreferences() { 191 if (mWorkPreferenceCategory == null) { 192 return; 193 } 194 final boolean isAvailable = isAvailable(); 195 mWorkPreferenceCategory.setVisible(isAvailable); 196 if (!isAvailable) { 197 return; 198 } 199 if (mWorkUsePersonalSounds == null) { 200 mWorkUsePersonalSounds = (TwoStatePreference) 201 mWorkPreferenceCategory.findPreference(KEY_WORK_USE_PERSONAL_SOUNDS); 202 mWorkUsePersonalSounds.setOnPreferenceChangeListener((Preference p, Object value) -> { 203 if ((boolean) value) { 204 UnifyWorkDialogFragment.show(mParent); 205 return false; 206 } else { 207 disableWorkSync(); 208 return true; 209 } 210 }); 211 } 212 if (mWorkPhoneRingtonePreference == null) { 213 mWorkPhoneRingtonePreference = initWorkPreference(mWorkPreferenceCategory, 214 KEY_WORK_PHONE_RINGTONE); 215 } 216 if (mWorkNotificationRingtonePreference == null) { 217 mWorkNotificationRingtonePreference = initWorkPreference(mWorkPreferenceCategory, 218 KEY_WORK_NOTIFICATION_RINGTONE); 219 } 220 if (mWorkAlarmRingtonePreference == null) { 221 mWorkAlarmRingtonePreference = initWorkPreference(mWorkPreferenceCategory, 222 KEY_WORK_ALARM_RINGTONE); 223 } 224 if (!mVoiceCapable) { 225 mWorkPhoneRingtonePreference.setVisible(false); 226 mWorkPhoneRingtonePreference = null; 227 } 228 229 final Context managedProfileContext = getManagedProfileContext(); 230 if (Settings.Secure.getIntForUser(managedProfileContext.getContentResolver(), 231 Settings.Secure.SYNC_PARENT_SOUNDS, 0, mManagedProfileId) == 1) { 232 enableWorkSyncSettings(); 233 } else { 234 disableWorkSyncSettings(); 235 } 236 } 237 enableWorkSync()238 void enableWorkSync() { 239 RingtoneManager.enableSyncFromParent(getManagedProfileContext()); 240 enableWorkSyncSettings(); 241 } 242 enableWorkSyncSettings()243 private void enableWorkSyncSettings() { 244 mWorkUsePersonalSounds.setChecked(true); 245 246 if (mWorkPhoneRingtonePreference != null) { 247 mWorkPhoneRingtonePreference.setSummary(R.string.work_sound_same_as_personal); 248 } 249 mWorkNotificationRingtonePreference.setSummary(R.string.work_sound_same_as_personal); 250 mWorkAlarmRingtonePreference.setSummary(R.string.work_sound_same_as_personal); 251 } 252 disableWorkSync()253 private void disableWorkSync() { 254 RingtoneManager.disableSyncFromParent(getManagedProfileContext()); 255 disableWorkSyncSettings(); 256 } 257 disableWorkSyncSettings()258 private void disableWorkSyncSettings() { 259 if (mWorkPhoneRingtonePreference != null) { 260 mWorkPhoneRingtonePreference.setEnabled(true); 261 } 262 mWorkNotificationRingtonePreference.setEnabled(true); 263 mWorkAlarmRingtonePreference.setEnabled(true); 264 265 updateWorkRingtoneSummaries(); 266 } 267 updateWorkRingtoneSummaries()268 private void updateWorkRingtoneSummaries() { 269 Context managedProfileContext = getManagedProfileContext(); 270 271 if (mWorkPhoneRingtonePreference != null) { 272 mWorkPhoneRingtonePreference.setSummary( 273 updateRingtoneName(managedProfileContext, RingtoneManager.TYPE_RINGTONE)); 274 } 275 mWorkNotificationRingtonePreference.setSummary( 276 updateRingtoneName(managedProfileContext, RingtoneManager.TYPE_NOTIFICATION)); 277 mWorkAlarmRingtonePreference.setSummary( 278 updateRingtoneName(managedProfileContext, RingtoneManager.TYPE_ALARM)); 279 } 280 onManagedProfileAdded(@serIdInt int profileId)281 public void onManagedProfileAdded(@UserIdInt int profileId) { 282 if (mManagedProfileId == UserHandle.USER_NULL) { 283 mManagedProfileId = profileId; 284 updateWorkPreferences(); 285 } 286 } 287 onManagedProfileRemoved(@serIdInt int profileId)288 public void onManagedProfileRemoved(@UserIdInt int profileId) { 289 if (mManagedProfileId == profileId) { 290 mManagedProfileId = mHelper.getManagedProfileId(mUserManager); 291 updateWorkPreferences(); 292 } 293 } 294 295 private final BroadcastReceiver mManagedProfileReceiver = new BroadcastReceiver() { 296 @Override 297 public void onReceive(Context context, Intent intent) { 298 final int userId = ((UserHandle) intent.getExtra(Intent.EXTRA_USER)).getIdentifier(); 299 switch (intent.getAction()) { 300 case Intent.ACTION_MANAGED_PROFILE_ADDED: { 301 onManagedProfileAdded(userId); 302 return; 303 } 304 case Intent.ACTION_MANAGED_PROFILE_REMOVED: { 305 onManagedProfileRemoved(userId); 306 return; 307 } 308 } 309 } 310 }; 311 312 public static class UnifyWorkDialogFragment extends InstrumentedDialogFragment 313 implements DialogInterface.OnClickListener { 314 private static final String TAG = "UnifyWorkDialogFragment"; 315 private static final int REQUEST_CODE = 200; 316 317 @Override getMetricsCategory()318 public int getMetricsCategory() { 319 return MetricsEvent.DIALOG_UNIFY_SOUND_SETTINGS; 320 } 321 322 @Override onCreateDialog(Bundle savedInstanceState)323 public Dialog onCreateDialog(Bundle savedInstanceState) { 324 return new AlertDialog.Builder(getActivity()) 325 .setTitle(R.string.work_sync_dialog_title) 326 .setMessage(R.string.work_sync_dialog_message) 327 .setPositiveButton(R.string.work_sync_dialog_yes, UnifyWorkDialogFragment.this) 328 .setNegativeButton(android.R.string.no, null) 329 .create(); 330 } 331 show(SoundSettings parent)332 public static void show(SoundSettings parent) { 333 FragmentManager fm = parent.getFragmentManager(); 334 if (fm.findFragmentByTag(TAG) == null) { 335 UnifyWorkDialogFragment fragment = new UnifyWorkDialogFragment(); 336 fragment.setTargetFragment(parent, REQUEST_CODE); 337 fragment.show(fm, TAG); 338 } 339 } 340 341 @Override onClick(DialogInterface dialog, int which)342 public void onClick(DialogInterface dialog, int which) { 343 SoundSettings soundSettings = (SoundSettings) getTargetFragment(); 344 if (soundSettings.isAdded()) { 345 soundSettings.enableWorkSync(); 346 } 347 } 348 } 349 350 } 351