• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.settings.notification;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.os.Bundle;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.os.Message;
25 import android.os.UserHandle;
26 import android.preference.SeekBarVolumizer;
27 import android.provider.SearchIndexableResource;
28 import android.support.annotation.VisibleForTesting;
29 import android.support.v7.preference.ListPreference;
30 import android.support.v7.preference.Preference;
31 import android.text.TextUtils;
32 
33 import com.android.internal.logging.nano.MetricsProto;
34 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
35 import com.android.settings.R;
36 import com.android.settings.RingtonePreference;
37 import com.android.settings.dashboard.DashboardFragment;
38 import com.android.settings.search.BaseSearchIndexProvider;
39 import com.android.settings.sound.HandsFreeProfileOutputPreferenceController;
40 import com.android.settings.sound.MediaOutputPreferenceController;
41 import com.android.settings.widget.PreferenceCategoryController;
42 import com.android.settings.widget.UpdatableListPreferenceDialogFragment;
43 import com.android.settingslib.core.AbstractPreferenceController;
44 import com.android.settingslib.core.instrumentation.Instrumentable;
45 import com.android.settingslib.core.lifecycle.Lifecycle;
46 
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.List;
50 
51 public class SoundSettings extends DashboardFragment {
52     private static final String TAG = "SoundSettings";
53 
54     private static final String SELECTED_PREFERENCE_KEY = "selected_preference";
55     private static final int REQUEST_CODE = 200;
56     private static final String KEY_ZEN_MODE = "zen_mode";
57     private static final int SAMPLE_CUTOFF = 2000;  // manually cap sample playback at 2 seconds
58 
59     @VisibleForTesting
60     static final int STOP_SAMPLE = 1;
61 
62     @VisibleForTesting
63     final VolumePreferenceCallback mVolumeCallback = new VolumePreferenceCallback();
64     @VisibleForTesting
65     final Handler mHandler = new Handler(Looper.getMainLooper()) {
66         @Override
67         public void handleMessage(Message msg) {
68             switch (msg.what) {
69                 case STOP_SAMPLE:
70                     mVolumeCallback.stopSample();
71                     break;
72             }
73         }
74     };
75 
76     private RingtonePreference mRequestPreference;
77     private UpdatableListPreferenceDialogFragment mDialogFragment;
78     private String mMediaOutputControllerKey;
79     private String mHfpOutputControllerKey;
80 
81     @Override
getMetricsCategory()82     public int getMetricsCategory() {
83         return MetricsEvent.SOUND;
84     }
85 
86     @Override
onCreate(Bundle savedInstanceState)87     public void onCreate(Bundle savedInstanceState) {
88         super.onCreate(savedInstanceState);
89         if (savedInstanceState != null) {
90             String selectedPreference = savedInstanceState.getString(SELECTED_PREFERENCE_KEY, null);
91             if (!TextUtils.isEmpty(selectedPreference)) {
92                 mRequestPreference = (RingtonePreference) findPreference(selectedPreference);
93             }
94 
95             UpdatableListPreferenceDialogFragment dialogFragment =
96                     (UpdatableListPreferenceDialogFragment) getFragmentManager()
97                             .findFragmentByTag(TAG);
98             mDialogFragment = dialogFragment;
99         }
100     }
101 
102     @Override
getHelpResource()103     public int getHelpResource() {
104         return R.string.help_url_sound;
105     }
106 
107     @Override
onPause()108     public void onPause() {
109         super.onPause();
110         mVolumeCallback.stopSample();
111     }
112 
113     @Override
onPreferenceTreeClick(Preference preference)114     public boolean onPreferenceTreeClick(Preference preference) {
115         if (preference instanceof RingtonePreference) {
116             mRequestPreference = (RingtonePreference) preference;
117             mRequestPreference.onPrepareRingtonePickerIntent(mRequestPreference.getIntent());
118             startActivityForResultAsUser(
119                     mRequestPreference.getIntent(),
120                     REQUEST_CODE,
121                     null,
122                     UserHandle.of(mRequestPreference.getUserId()));
123             return true;
124         }
125         return super.onPreferenceTreeClick(preference);
126     }
127 
128     @Override
onDisplayPreferenceDialog(Preference preference)129     public void onDisplayPreferenceDialog(Preference preference) {
130         final int metricsCategory;
131         if (mHfpOutputControllerKey.equals(preference.getKey())) {
132             metricsCategory = MetricsProto.MetricsEvent.DIALOG_SWITCH_HFP_DEVICES;
133         } else if (mMediaOutputControllerKey.equals(preference.getKey())) {
134             metricsCategory = MetricsProto.MetricsEvent.DIALOG_SWITCH_A2DP_DEVICES;
135         } else {
136             metricsCategory = Instrumentable.METRICS_CATEGORY_UNKNOWN;
137         }
138 
139         mDialogFragment = UpdatableListPreferenceDialogFragment.
140                 newInstance(preference.getKey(), metricsCategory);
141         mDialogFragment.setTargetFragment(this, 0);
142         mDialogFragment.show(getFragmentManager(), TAG);
143     }
144 
145     @Override
getLogTag()146     protected String getLogTag() {
147         return TAG;
148     }
149 
150     @Override
getPreferenceScreenResId()151     protected int getPreferenceScreenResId() {
152         return R.xml.sound_settings;
153     }
154 
155     @Override
createPreferenceControllers(Context context)156     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
157         return buildPreferenceControllers(context, this, getLifecycle());
158     }
159 
160     @Override
onActivityResult(int requestCode, int resultCode, Intent data)161     public void onActivityResult(int requestCode, int resultCode, Intent data) {
162         if (mRequestPreference != null) {
163             mRequestPreference.onActivityResult(requestCode, resultCode, data);
164             mRequestPreference = null;
165         }
166     }
167 
168     @Override
onSaveInstanceState(Bundle outState)169     public void onSaveInstanceState(Bundle outState) {
170         super.onSaveInstanceState(outState);
171         if (mRequestPreference != null) {
172             outState.putString(SELECTED_PREFERENCE_KEY, mRequestPreference.getKey());
173         }
174     }
175 
176     @Override
onAttach(Context context)177     public void onAttach(Context context) {
178         super.onAttach(context);
179         ArrayList<VolumeSeekBarPreferenceController> volumeControllers = new ArrayList<>();
180         volumeControllers.add(use(AlarmVolumePreferenceController.class));
181         volumeControllers.add(use(MediaVolumePreferenceController.class));
182         volumeControllers.add(use(RingVolumePreferenceController.class));
183         volumeControllers.add(use(NotificationVolumePreferenceController.class));
184         volumeControllers.add(use(CallVolumePreferenceController.class));
185 
186         use(MediaOutputPreferenceController.class).setCallback(listPreference ->
187                 onPreferenceDataChanged(listPreference));
188         mMediaOutputControllerKey = use(MediaOutputPreferenceController.class).getPreferenceKey();
189         use(HandsFreeProfileOutputPreferenceController.class).setCallback(listPreference ->
190             onPreferenceDataChanged(listPreference));
191         mHfpOutputControllerKey =
192                 use(HandsFreeProfileOutputPreferenceController.class).getPreferenceKey();
193 
194         for (VolumeSeekBarPreferenceController controller : volumeControllers) {
195             controller.setCallback(mVolumeCallback);
196             getLifecycle().addObserver(controller);
197         }
198     }
199 
200     // === Volumes ===
201 
202     final class VolumePreferenceCallback implements VolumeSeekBarPreference.Callback {
203         private SeekBarVolumizer mCurrent;
204 
205         @Override
onSampleStarting(SeekBarVolumizer sbv)206         public void onSampleStarting(SeekBarVolumizer sbv) {
207             if (mCurrent != null && mCurrent != sbv) {
208                 mCurrent.stopSample();
209             }
210             mCurrent = sbv;
211             if (mCurrent != null) {
212                 mHandler.removeMessages(STOP_SAMPLE);
213                 mHandler.sendEmptyMessageDelayed(STOP_SAMPLE, SAMPLE_CUTOFF);
214             }
215         }
216 
217         @Override
onStreamValueChanged(int stream, int progress)218         public void onStreamValueChanged(int stream, int progress) {
219             if (mCurrent != null) {
220                 mHandler.removeMessages(STOP_SAMPLE);
221                 mHandler.sendEmptyMessageDelayed(STOP_SAMPLE, SAMPLE_CUTOFF);
222             }
223         }
224 
stopSample()225         public void stopSample() {
226             if (mCurrent != null) {
227                 mCurrent.stopSample();
228             }
229         }
230     }
231 
buildPreferenceControllers(Context context, SoundSettings fragment, Lifecycle lifecycle)232     private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
233             SoundSettings fragment, Lifecycle lifecycle) {
234         final List<AbstractPreferenceController> controllers = new ArrayList<>();
235         controllers.add(new ZenModePreferenceController(context, lifecycle, KEY_ZEN_MODE));
236 
237         // Volumes are added via xml
238 
239         // === Phone & notification ringtone ===
240         controllers.add(new PhoneRingtonePreferenceController(context));
241         controllers.add(new AlarmRingtonePreferenceController(context));
242         controllers.add(new NotificationRingtonePreferenceController(context));
243 
244         // === Work Sound Settings ===
245         controllers.add(new WorkSoundPreferenceController(context, fragment, lifecycle));
246 
247         // === Other Sound Settings ===
248         final DialPadTonePreferenceController dialPadTonePreferenceController =
249                 new DialPadTonePreferenceController(context, fragment, lifecycle);
250         final ScreenLockSoundPreferenceController screenLockSoundPreferenceController =
251                 new ScreenLockSoundPreferenceController(context, fragment, lifecycle);
252         final ChargingSoundPreferenceController chargingSoundPreferenceController =
253                 new ChargingSoundPreferenceController(context, fragment, lifecycle);
254         final DockingSoundPreferenceController dockingSoundPreferenceController =
255                 new DockingSoundPreferenceController(context, fragment, lifecycle);
256         final TouchSoundPreferenceController touchSoundPreferenceController =
257                 new TouchSoundPreferenceController(context, fragment, lifecycle);
258         final VibrateOnTouchPreferenceController vibrateOnTouchPreferenceController =
259                 new VibrateOnTouchPreferenceController(context, fragment, lifecycle);
260         final DockAudioMediaPreferenceController dockAudioMediaPreferenceController =
261                 new DockAudioMediaPreferenceController(context, fragment, lifecycle);
262         final BootSoundPreferenceController bootSoundPreferenceController =
263                 new BootSoundPreferenceController(context);
264         final EmergencyTonePreferenceController emergencyTonePreferenceController =
265                 new EmergencyTonePreferenceController(context, fragment, lifecycle);
266 
267         controllers.add(dialPadTonePreferenceController);
268         controllers.add(screenLockSoundPreferenceController);
269         controllers.add(chargingSoundPreferenceController);
270         controllers.add(dockingSoundPreferenceController);
271         controllers.add(touchSoundPreferenceController);
272         controllers.add(vibrateOnTouchPreferenceController);
273         controllers.add(dockAudioMediaPreferenceController);
274         controllers.add(bootSoundPreferenceController);
275         controllers.add(emergencyTonePreferenceController);
276         controllers.add(new PreferenceCategoryController(context,
277                 "other_sounds_and_vibrations_category").setChildren(
278                 Arrays.asList(dialPadTonePreferenceController,
279                         screenLockSoundPreferenceController,
280                         chargingSoundPreferenceController,
281                         dockingSoundPreferenceController,
282                         touchSoundPreferenceController,
283                         vibrateOnTouchPreferenceController,
284                         dockAudioMediaPreferenceController,
285                         bootSoundPreferenceController,
286                         emergencyTonePreferenceController)));
287 
288         return controllers;
289     }
290 
291     // === Indexing ===
292 
293     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
294             new BaseSearchIndexProvider() {
295 
296                 public List<SearchIndexableResource> getXmlResourcesToIndex(
297                         Context context, boolean enabled) {
298                     final SearchIndexableResource sir = new SearchIndexableResource(context);
299                     sir.xmlResId = R.xml.sound_settings;
300                     return Arrays.asList(sir);
301                 }
302 
303                 @Override
304                 public List<AbstractPreferenceController> createPreferenceControllers(
305                         Context context) {
306                     return buildPreferenceControllers(context, null /* fragment */,
307                             null /* lifecycle */);
308                 }
309 
310                 @Override
311                 public List<String> getNonIndexableKeys(Context context) {
312                     List<String> keys = super.getNonIndexableKeys(context);
313                     // Duplicate results
314                     keys.add((new ZenModePreferenceController(context, null, KEY_ZEN_MODE))
315                             .getPreferenceKey());
316                     return keys;
317                 }
318             };
319 
320     // === Work Sound Settings ===
321 
enableWorkSync()322     void enableWorkSync() {
323         final WorkSoundPreferenceController workSoundController =
324                 use(WorkSoundPreferenceController.class);
325         if (workSoundController != null) {
326             workSoundController.enableWorkSync();
327         }
328     }
329 
onPreferenceDataChanged(ListPreference preference)330     private void onPreferenceDataChanged(ListPreference preference) {
331         if (mDialogFragment != null) {
332             mDialogFragment.onListPreferenceUpdated(preference);
333         }
334     }
335 }