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
17package com.android.dialer.settings;
18
19import android.content.Context;
20import android.media.RingtoneManager;
21import android.os.Build;
22import android.os.Bundle;
23import android.os.Handler;
24import android.os.Message;
25import android.os.Vibrator;
26import android.preference.CheckBoxPreference;
27import android.preference.ListPreference;
28import android.preference.Preference;
29import android.preference.PreferenceFragment;
30import android.preference.PreferenceScreen;
31import android.provider.Settings;
32import android.telephony.CarrierConfigManager;
33import android.telephony.TelephonyManager;
34import android.widget.Toast;
35
36import com.android.contacts.common.compat.SdkVersionOverride;
37import com.android.dialer.R;
38import com.android.dialer.compat.SettingsCompat;
39import com.android.phone.common.util.SettingsUtil;
40
41public 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
82    public Context getContext() {
83        return getActivity();
84    }
85
86    @Override
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
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
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
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     */
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     */
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     */
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     */
234    private boolean hasVibrator() {
235        Vibrator vibrator = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE);
236        return vibrator != null && vibrator.hasVibrator();
237    }
238
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