Home | History | Annotate | Download | only in notification
      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 
     79     public WorkSoundPreferenceController(Context context, SoundSettings parent,
     80             Lifecycle lifecycle) {
     81         this(context, parent, lifecycle, new AudioHelper(context));
     82     }
     83 
     84     @VisibleForTesting
     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
     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
    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
    117     public void onPause() {
    118         mContext.unregisterReceiver(mManagedProfileReceiver);
    119     }
    120 
    121     @Override
    122     public String getPreferenceKey() {
    123         return KEY_WORK_CATEGORY;
    124     }
    125 
    126     @Override
    127     public boolean isAvailable() {
    128         return mHelper.getManagedProfileId(mUserManager) != UserHandle.USER_NULL
    129                 && shouldShowRingtoneSettings();
    130     }
    131 
    132     @Override
    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
    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 
    162     private boolean shouldShowRingtoneSettings() {
    163         return !mHelper.isSingleVolume();
    164     }
    165 
    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 
    175     private Context getManagedProfileContext() {
    176         if (mManagedProfileId == UserHandle.USER_NULL) {
    177             return null;
    178         }
    179         return mHelper.createPackageContextAsUser(mManagedProfileId);
    180     }
    181 
    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 
    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 
    240     void enableWorkSync() {
    241         RingtoneManager.enableSyncFromParent(getManagedProfileContext());
    242         enableWorkSyncSettings();
    243     }
    244 
    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 
    255     private void disableWorkSync() {
    256         RingtoneManager.disableSyncFromParent(getManagedProfileContext());
    257         disableWorkSyncSettings();
    258     }
    259 
    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 
    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 
    283     public void onManagedProfileAdded(@UserIdInt int profileId) {
    284         if (mManagedProfileId == UserHandle.USER_NULL) {
    285             mManagedProfileId = profileId;
    286             updateWorkPreferences();
    287         }
    288     }
    289 
    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
    320         public int getMetricsCategory() {
    321             return MetricsEvent.DIALOG_UNIFY_SOUND_SETTINGS;
    322         }
    323 
    324         @Override
    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 
    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
    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