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.settings.notification;
18
19import static com.android.settings.notification.SettingPref.TYPE_GLOBAL;
20import static com.android.settings.notification.SettingPref.TYPE_SYSTEM;
21
22import android.content.ContentResolver;
23import android.content.Context;
24import android.content.res.Resources;
25import android.database.ContentObserver;
26import android.media.AudioManager;
27import android.net.Uri;
28import android.os.Bundle;
29import android.os.Handler;
30import android.os.Vibrator;
31import android.provider.SearchIndexableResource;
32import android.provider.Settings.Global;
33import android.provider.Settings.System;
34import android.telephony.TelephonyManager;
35
36import com.android.internal.logging.MetricsLogger;
37import com.android.settings.R;
38import com.android.settings.SettingsPreferenceFragment;
39import com.android.settings.Utils;
40import com.android.settings.search.BaseSearchIndexProvider;
41import com.android.settings.search.Indexable;
42
43import java.util.ArrayList;
44import java.util.Arrays;
45import java.util.List;
46
47public class OtherSoundSettings extends SettingsPreferenceFragment implements Indexable {
48    private static final String TAG = "OtherSoundSettings";
49
50    private static final int DEFAULT_ON = 1;
51
52    private static final int EMERGENCY_TONE_SILENT = 0;
53    private static final int EMERGENCY_TONE_ALERT = 1;
54    private static final int EMERGENCY_TONE_VIBRATE = 2;
55    private static final int DEFAULT_EMERGENCY_TONE = EMERGENCY_TONE_SILENT;
56
57    private static final int DOCK_AUDIO_MEDIA_DISABLED = 0;
58    private static final int DOCK_AUDIO_MEDIA_ENABLED = 1;
59    private static final int DEFAULT_DOCK_AUDIO_MEDIA = DOCK_AUDIO_MEDIA_DISABLED;
60
61    private static final String KEY_DIAL_PAD_TONES = "dial_pad_tones";
62    private static final String KEY_SCREEN_LOCKING_SOUNDS = "screen_locking_sounds";
63    private static final String KEY_CHARGING_SOUNDS = "charging_sounds";
64    private static final String KEY_DOCKING_SOUNDS = "docking_sounds";
65    private static final String KEY_TOUCH_SOUNDS = "touch_sounds";
66    private static final String KEY_VIBRATE_ON_TOUCH = "vibrate_on_touch";
67    private static final String KEY_DOCK_AUDIO_MEDIA = "dock_audio_media";
68    private static final String KEY_EMERGENCY_TONE = "emergency_tone";
69
70    private static final SettingPref PREF_DIAL_PAD_TONES = new SettingPref(
71            TYPE_SYSTEM, KEY_DIAL_PAD_TONES, System.DTMF_TONE_WHEN_DIALING, DEFAULT_ON) {
72        @Override
73        public boolean isApplicable(Context context) {
74            return Utils.isVoiceCapable(context);
75        }
76    };
77
78    private static final SettingPref PREF_SCREEN_LOCKING_SOUNDS = new SettingPref(
79            TYPE_SYSTEM, KEY_SCREEN_LOCKING_SOUNDS, System.LOCKSCREEN_SOUNDS_ENABLED, DEFAULT_ON);
80
81    private static final SettingPref PREF_CHARGING_SOUNDS = new SettingPref(
82            TYPE_GLOBAL, KEY_CHARGING_SOUNDS, Global.CHARGING_SOUNDS_ENABLED, DEFAULT_ON);
83
84    private static final SettingPref PREF_DOCKING_SOUNDS = new SettingPref(
85            TYPE_GLOBAL, KEY_DOCKING_SOUNDS, Global.DOCK_SOUNDS_ENABLED, DEFAULT_ON) {
86        @Override
87        public boolean isApplicable(Context context) {
88            return hasDockSettings(context);
89        }
90    };
91
92    private static final SettingPref PREF_TOUCH_SOUNDS = new SettingPref(
93            TYPE_SYSTEM, KEY_TOUCH_SOUNDS, System.SOUND_EFFECTS_ENABLED, DEFAULT_ON) {
94        @Override
95        protected boolean setSetting(Context context, int value) {
96            final AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
97            if (value != 0) {
98                am.loadSoundEffects();
99            } else {
100                am.unloadSoundEffects();
101            }
102            return super.setSetting(context, value);
103        }
104    };
105
106    private static final SettingPref PREF_VIBRATE_ON_TOUCH = new SettingPref(
107            TYPE_SYSTEM, KEY_VIBRATE_ON_TOUCH, System.HAPTIC_FEEDBACK_ENABLED, DEFAULT_ON) {
108        @Override
109        public boolean isApplicable(Context context) {
110            return hasHaptic(context);
111        }
112    };
113
114    private static final SettingPref PREF_DOCK_AUDIO_MEDIA = new SettingPref(
115            TYPE_GLOBAL, KEY_DOCK_AUDIO_MEDIA, Global.DOCK_AUDIO_MEDIA_ENABLED,
116            DEFAULT_DOCK_AUDIO_MEDIA, DOCK_AUDIO_MEDIA_DISABLED, DOCK_AUDIO_MEDIA_ENABLED) {
117        @Override
118        public boolean isApplicable(Context context) {
119            return hasDockSettings(context);
120        }
121
122        @Override
123        protected String getCaption(Resources res, int value) {
124            switch(value) {
125                case DOCK_AUDIO_MEDIA_DISABLED:
126                    return res.getString(R.string.dock_audio_media_disabled);
127                case DOCK_AUDIO_MEDIA_ENABLED:
128                    return res.getString(R.string.dock_audio_media_enabled);
129                default:
130                    throw new IllegalArgumentException();
131            }
132        }
133    };
134
135    private static final SettingPref PREF_EMERGENCY_TONE = new SettingPref(
136            TYPE_GLOBAL, KEY_EMERGENCY_TONE, Global.EMERGENCY_TONE, DEFAULT_EMERGENCY_TONE,
137            EMERGENCY_TONE_ALERT, EMERGENCY_TONE_VIBRATE, EMERGENCY_TONE_SILENT) {
138        @Override
139        public boolean isApplicable(Context context) {
140            final int activePhoneType = TelephonyManager.getDefault().getCurrentPhoneType();
141            return activePhoneType == TelephonyManager.PHONE_TYPE_CDMA;
142        }
143
144        @Override
145        protected String getCaption(Resources res, int value) {
146            switch(value) {
147                case EMERGENCY_TONE_SILENT:
148                    return res.getString(R.string.emergency_tone_silent);
149                case EMERGENCY_TONE_ALERT:
150                    return res.getString(R.string.emergency_tone_alert);
151                case EMERGENCY_TONE_VIBRATE:
152                    return res.getString(R.string.emergency_tone_vibrate);
153                default:
154                    throw new IllegalArgumentException();
155            }
156        }
157    };
158
159    private static final SettingPref[] PREFS = {
160        PREF_DIAL_PAD_TONES,
161        PREF_SCREEN_LOCKING_SOUNDS,
162        PREF_CHARGING_SOUNDS,
163        PREF_DOCKING_SOUNDS,
164        PREF_TOUCH_SOUNDS,
165        PREF_VIBRATE_ON_TOUCH,
166        PREF_DOCK_AUDIO_MEDIA,
167        PREF_EMERGENCY_TONE,
168    };
169
170    private final SettingsObserver mSettingsObserver = new SettingsObserver();
171
172    private Context mContext;
173
174    @Override
175    protected int getMetricsCategory() {
176        return MetricsLogger.NOTIFICATION_OTHER_SOUND;
177    }
178
179    @Override
180    protected int getHelpResource() {
181        return R.string.help_uri_other_sounds;
182    }
183
184    @Override
185    public void onCreate(Bundle savedInstanceState) {
186        super.onCreate(savedInstanceState);
187
188        addPreferencesFromResource(R.xml.other_sound_settings);
189
190        mContext = getActivity();
191
192        for (SettingPref pref : PREFS) {
193            pref.init(this);
194        }
195    }
196
197    @Override
198    public void onResume() {
199        super.onResume();
200        mSettingsObserver.register(true);
201    }
202
203    @Override
204    public void onPause() {
205        super.onPause();
206        mSettingsObserver.register(false);
207    }
208
209    private static boolean hasDockSettings(Context context) {
210        return context.getResources().getBoolean(R.bool.has_dock_settings);
211    }
212
213    private static boolean hasHaptic(Context context) {
214        final Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
215        return vibrator != null && vibrator.hasVibrator();
216    }
217
218    // === Callbacks ===
219
220    private final class SettingsObserver extends ContentObserver {
221        public SettingsObserver() {
222            super(new Handler());
223        }
224
225        public void register(boolean register) {
226            final ContentResolver cr = getContentResolver();
227            if (register) {
228                for (SettingPref pref : PREFS) {
229                    cr.registerContentObserver(pref.getUri(), false, this);
230                }
231            } else {
232                cr.unregisterContentObserver(this);
233            }
234        }
235
236        @Override
237        public void onChange(boolean selfChange, Uri uri) {
238            super.onChange(selfChange, uri);
239            for (SettingPref pref : PREFS) {
240                if (pref.getUri().equals(uri)) {
241                    pref.update(mContext);
242                    return;
243                }
244            }
245        }
246    }
247
248    // === Indexing ===
249
250    public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
251            new BaseSearchIndexProvider() {
252
253        public List<SearchIndexableResource> getXmlResourcesToIndex(
254                Context context, boolean enabled) {
255            final SearchIndexableResource sir = new SearchIndexableResource(context);
256            sir.xmlResId = R.xml.other_sound_settings;
257            return Arrays.asList(sir);
258        }
259
260        public List<String> getNonIndexableKeys(Context context) {
261            final ArrayList<String> rt = new ArrayList<String>();
262            for (SettingPref pref : PREFS) {
263                if (!pref.isApplicable(context)) {
264                    rt.add(pref.getKey());
265                }
266            }
267            return rt;
268        }
269    };
270}
271