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