1 /*
2  * Copyright (C) 2014 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.dialer.settings;
18 
19 import android.content.Context;
20 import android.media.RingtoneManager;
21 import android.os.Build;
22 import android.os.Bundle;
23 import android.os.Handler;
24 import android.os.Message;
25 import android.os.Vibrator;
26 import android.preference.CheckBoxPreference;
27 import android.preference.ListPreference;
28 import android.preference.Preference;
29 import android.preference.PreferenceFragment;
30 import android.preference.PreferenceScreen;
31 import android.provider.Settings;
32 import android.telephony.CarrierConfigManager;
33 import android.telephony.TelephonyManager;
34 import android.widget.Toast;
35 
36 import com.android.contacts.common.compat.SdkVersionOverride;
37 import com.android.dialer.R;
38 import com.android.dialer.compat.SettingsCompat;
39 import com.android.phone.common.util.SettingsUtil;
40 
41 public class SoundSettingsFragment extends PreferenceFragment
42         implements Preference.OnPreferenceChangeListener {
43 
44     private static final int NO_DTMF_TONE = 0;
45     private static final int PLAY_DTMF_TONE = 1;
46 
47     private static final int NO_VIBRATION_FOR_CALLS = 0;
48     private static final int DO_VIBRATION_FOR_CALLS = 1;
49 
50 
51     private static final int DTMF_TONE_TYPE_NORMAL = 0;
52 
53     private static final int SHOW_CARRIER_SETTINGS = 0;
54     private static final int HIDE_CARRIER_SETTINGS = 1;
55 
56     private static final int MSG_UPDATE_RINGTONE_SUMMARY = 1;
57 
58     private Preference mRingtonePreference;
59     private CheckBoxPreference mVibrateWhenRinging;
60     private CheckBoxPreference mPlayDtmfTone;
61     private ListPreference mDtmfToneLength;
62 
63     private final Runnable mRingtoneLookupRunnable = new Runnable() {
64         @Override
65         public void run() {
66             updateRingtonePreferenceSummary();
67         }
68     };
69 
70     private final Handler mRingtoneLookupComplete = new Handler() {
71         @Override
72         public void handleMessage(Message msg) {
73             switch (msg.what) {
74                 case MSG_UPDATE_RINGTONE_SUMMARY:
75                     mRingtonePreference.setSummary((CharSequence) msg.obj);
76                     break;
77             }
78         }
79     };
80 
81     @Override
getContext()82     public Context getContext() {
83         return getActivity();
84     }
85 
86     @Override
onCreate(Bundle savedInstanceState)87     public void onCreate(Bundle savedInstanceState) {
88         super.onCreate(savedInstanceState);
89 
90         addPreferencesFromResource(R.xml.sound_settings);
91 
92         Context context = getActivity();
93 
94         mRingtonePreference = findPreference(context.getString(R.string.ringtone_preference_key));
95         mVibrateWhenRinging = (CheckBoxPreference) findPreference(
96                 context.getString(R.string.vibrate_on_preference_key));
97         mPlayDtmfTone = (CheckBoxPreference) findPreference(
98                 context.getString(R.string.play_dtmf_preference_key));
99         mDtmfToneLength = (ListPreference) findPreference(
100                 context.getString(R.string.dtmf_tone_length_preference_key));
101 
102         if (hasVibrator()) {
103             mVibrateWhenRinging.setOnPreferenceChangeListener(this);
104         } else {
105             getPreferenceScreen().removePreference(mVibrateWhenRinging);
106             mVibrateWhenRinging = null;
107         }
108 
109         mPlayDtmfTone.setOnPreferenceChangeListener(this);
110         mPlayDtmfTone.setChecked(shouldPlayDtmfTone());
111 
112         TelephonyManager telephonyManager =
113                 (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
114         if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M
115                 && telephonyManager.canChangeDtmfToneLength()
116                 && (telephonyManager.isWorldPhone() || !shouldHideCarrierSettings())) {
117             mDtmfToneLength.setOnPreferenceChangeListener(this);
118             mDtmfToneLength.setValueIndex(
119                     Settings.System.getInt(context.getContentResolver(),
120                         Settings.System.DTMF_TONE_TYPE_WHEN_DIALING,
121                         DTMF_TONE_TYPE_NORMAL));
122         } else {
123             getPreferenceScreen().removePreference(mDtmfToneLength);
124             mDtmfToneLength = null;
125         }
126     }
127 
128     @Override
onResume()129     public void onResume() {
130         super.onResume();
131 
132         if (!SettingsCompat.System.canWrite(getContext())) {
133             // If the user launches this setting fragment, then toggles the WRITE_SYSTEM_SETTINGS
134             // AppOp, then close the fragment since there is nothing useful to do.
135             getActivity().onBackPressed();
136             return;
137         }
138 
139         if (mVibrateWhenRinging != null) {
140             mVibrateWhenRinging.setChecked(shouldVibrateWhenRinging());
141         }
142 
143         // Lookup the ringtone name asynchronously.
144         new Thread(mRingtoneLookupRunnable).start();
145     }
146 
147     /**
148      * Supports onPreferenceChangeListener to look for preference changes.
149      *
150      * @param preference The preference to be changed
151      * @param objValue The value of the selection, NOT its localized display value.
152      */
153     @Override
onPreferenceChange(Preference preference, Object objValue)154     public boolean onPreferenceChange(Preference preference, Object objValue) {
155         if (!SettingsCompat.System.canWrite(getContext())) {
156             // A user shouldn't be able to get here, but this protects against monkey crashes.
157             Toast.makeText(
158                     getContext(),
159                     getResources().getString(R.string.toast_cannot_write_system_settings),
160                     Toast.LENGTH_SHORT).show();
161             return true;
162         }
163         if (preference == mVibrateWhenRinging) {
164             boolean doVibrate = (Boolean) objValue;
165             Settings.System.putInt(getActivity().getContentResolver(),
166                     Settings.System.VIBRATE_WHEN_RINGING,
167                     doVibrate ? DO_VIBRATION_FOR_CALLS : NO_VIBRATION_FOR_CALLS);
168         } else if (preference == mDtmfToneLength) {
169             int index = mDtmfToneLength.findIndexOfValue((String) objValue);
170             Settings.System.putInt(getActivity().getContentResolver(),
171                     Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, index);
172         }
173         return true;
174     }
175 
176     /**
177      * Click listener for toggle events.
178      */
179     @Override
onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)180     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
181         if (!SettingsCompat.System.canWrite(getContext())) {
182             Toast.makeText(
183                     getContext(),
184                     getResources().getString(R.string.toast_cannot_write_system_settings),
185                     Toast.LENGTH_SHORT).show();
186             return true;
187         }
188         if (preference == mPlayDtmfTone) {
189             Settings.System.putInt(getActivity().getContentResolver(),
190                     Settings.System.DTMF_TONE_WHEN_DIALING,
191                     mPlayDtmfTone.isChecked() ? PLAY_DTMF_TONE : NO_DTMF_TONE);
192         }
193         return true;
194     }
195 
196     /**
197      * Updates the summary text on the ringtone preference with the name of the ringtone.
198      */
updateRingtonePreferenceSummary()199     private void updateRingtonePreferenceSummary() {
200         SettingsUtil.updateRingtoneName(
201                 getActivity(),
202                 mRingtoneLookupComplete,
203                 RingtoneManager.TYPE_RINGTONE,
204                 mRingtonePreference.getKey(),
205                 MSG_UPDATE_RINGTONE_SUMMARY);
206     }
207 
208     /**
209      * Obtain the value for "vibrate when ringing" setting. The default value is false.
210      *
211      * Watch out: if the setting is missing in the device, this will try obtaining the old
212      * "vibrate on ring" setting from AudioManager, and save the previous setting to the new one.
213      */
shouldVibrateWhenRinging()214     private boolean shouldVibrateWhenRinging() {
215         int vibrateWhenRingingSetting = Settings.System.getInt(getActivity().getContentResolver(),
216                 Settings.System.VIBRATE_WHEN_RINGING,
217                 NO_VIBRATION_FOR_CALLS);
218         return hasVibrator() && (vibrateWhenRingingSetting == DO_VIBRATION_FOR_CALLS);
219     }
220 
221     /**
222      * Obtains the value for dialpad/DTMF tones. The default value is true.
223      */
shouldPlayDtmfTone()224     private boolean shouldPlayDtmfTone() {
225         int dtmfToneSetting = Settings.System.getInt(getActivity().getContentResolver(),
226                 Settings.System.DTMF_TONE_WHEN_DIALING,
227                 PLAY_DTMF_TONE);
228         return dtmfToneSetting == PLAY_DTMF_TONE;
229     }
230 
231     /**
232      * Whether the device hardware has a vibrator.
233      */
hasVibrator()234     private boolean hasVibrator() {
235         Vibrator vibrator = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE);
236         return vibrator != null && vibrator.hasVibrator();
237     }
238 
shouldHideCarrierSettings()239     private boolean shouldHideCarrierSettings() {
240         CarrierConfigManager configManager = (CarrierConfigManager) getActivity().getSystemService(
241                 Context.CARRIER_CONFIG_SERVICE);
242         return configManager.getConfig().getBoolean(
243                 CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL);
244     }
245 }
246