RingtoneManager.java revision 322780496fbe994698c0de63deb17f498b66a6ee
1/*
2 * Copyright (C) 2007 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 android.media;
18
19import com.android.internal.database.SortCursor;
20
21import android.annotation.SdkConstant;
22import android.annotation.SdkConstant.SdkConstantType;
23import android.app.Activity;
24import android.content.ContentUris;
25import android.content.Context;
26import android.content.res.AssetFileDescriptor;
27import android.database.Cursor;
28import android.net.Uri;
29import android.os.Environment;
30import android.provider.MediaStore;
31import android.provider.Settings;
32import android.provider.Settings.System;
33import android.util.Log;
34
35import java.util.ArrayList;
36import java.util.List;
37
38/**
39 * RingtoneManager provides access to ringtones, notification, and other types
40 * of sounds. It manages querying the different media providers and combines the
41 * results into a single cursor. It also provides a {@link Ringtone} for each
42 * ringtone. We generically call these sounds ringtones, however the
43 * {@link #TYPE_RINGTONE} refers to the type of sounds that are suitable for the
44 * phone ringer.
45 * <p>
46 * To show a ringtone picker to the user, use the
47 * {@link #ACTION_RINGTONE_PICKER} intent to launch the picker as a subactivity.
48 *
49 * @see Ringtone
50 */
51public class RingtoneManager {
52
53    private static final String TAG = "RingtoneManager";
54
55    // Make sure these are in sync with attrs.xml:
56    // <attr name="ringtoneType">
57
58    /**
59     * Type that refers to sounds that are used for the phone ringer.
60     */
61    public static final int TYPE_RINGTONE = 1;
62
63    /**
64     * Type that refers to sounds that are used for notifications.
65     */
66    public static final int TYPE_NOTIFICATION = 2;
67
68    /**
69     * Type that refers to sounds that are used for the alarm.
70     */
71    public static final int TYPE_ALARM = 4;
72
73    /**
74     * All types of sounds.
75     */
76    public static final int TYPE_ALL = TYPE_RINGTONE | TYPE_NOTIFICATION | TYPE_ALARM;
77
78    // </attr>
79
80    /**
81     * Activity Action: Shows a ringtone picker.
82     * <p>
83     * Input: {@link #EXTRA_RINGTONE_EXISTING_URI},
84     * {@link #EXTRA_RINGTONE_SHOW_DEFAULT},
85     * {@link #EXTRA_RINGTONE_SHOW_SILENT}, {@link #EXTRA_RINGTONE_TYPE},
86     * {@link #EXTRA_RINGTONE_DEFAULT_URI}, {@link #EXTRA_RINGTONE_TITLE},
87     * <p>
88     * Output: {@link #EXTRA_RINGTONE_PICKED_URI}.
89     */
90    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
91    public static final String ACTION_RINGTONE_PICKER = "android.intent.action.RINGTONE_PICKER";
92
93    /**
94     * Given to the ringtone picker as a boolean. Whether to show an item for
95     * "Default".
96     *
97     * @see #ACTION_RINGTONE_PICKER
98     */
99    public static final String EXTRA_RINGTONE_SHOW_DEFAULT =
100            "android.intent.extra.ringtone.SHOW_DEFAULT";
101
102    /**
103     * Given to the ringtone picker as a boolean. Whether to show an item for
104     * "Silent". If the "Silent" item is picked,
105     * {@link #EXTRA_RINGTONE_PICKED_URI} will be null.
106     *
107     * @see #ACTION_RINGTONE_PICKER
108     */
109    public static final String EXTRA_RINGTONE_SHOW_SILENT =
110            "android.intent.extra.ringtone.SHOW_SILENT";
111
112    /**
113     * Given to the ringtone picker as a boolean. Whether to include DRM ringtones.
114     * @deprecated DRM ringtones are no longer supported
115     */
116    @Deprecated
117    public static final String EXTRA_RINGTONE_INCLUDE_DRM =
118            "android.intent.extra.ringtone.INCLUDE_DRM";
119
120    /**
121     * Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the
122     * current ringtone, which will be used to show a checkmark next to the item
123     * for this {@link Uri}. If showing an item for "Default" (@see
124     * {@link #EXTRA_RINGTONE_SHOW_DEFAULT}), this can also be one of
125     * {@link System#DEFAULT_RINGTONE_URI},
126     * {@link System#DEFAULT_NOTIFICATION_URI}, or
127     * {@link System#DEFAULT_ALARM_ALERT_URI} to have the "Default" item
128     * checked.
129     *
130     * @see #ACTION_RINGTONE_PICKER
131     */
132    public static final String EXTRA_RINGTONE_EXISTING_URI =
133            "android.intent.extra.ringtone.EXISTING_URI";
134
135    /**
136     * Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the
137     * ringtone to play when the user attempts to preview the "Default"
138     * ringtone. This can be one of {@link System#DEFAULT_RINGTONE_URI},
139     * {@link System#DEFAULT_NOTIFICATION_URI}, or
140     * {@link System#DEFAULT_ALARM_ALERT_URI} to have the "Default" point to
141     * the current sound for the given default sound type. If you are showing a
142     * ringtone picker for some other type of sound, you are free to provide any
143     * {@link Uri} here.
144     */
145    public static final String EXTRA_RINGTONE_DEFAULT_URI =
146            "android.intent.extra.ringtone.DEFAULT_URI";
147
148    /**
149     * Given to the ringtone picker as an int. Specifies which ringtone type(s) should be
150     * shown in the picker. One or more of {@link #TYPE_RINGTONE},
151     * {@link #TYPE_NOTIFICATION}, {@link #TYPE_ALARM}, or {@link #TYPE_ALL}
152     * (bitwise-ored together).
153     */
154    public static final String EXTRA_RINGTONE_TYPE = "android.intent.extra.ringtone.TYPE";
155
156    /**
157     * Given to the ringtone picker as a {@link CharSequence}. The title to
158     * show for the ringtone picker. This has a default value that is suitable
159     * in most cases.
160     */
161    public static final String EXTRA_RINGTONE_TITLE = "android.intent.extra.ringtone.TITLE";
162
163    /**
164     * Returned from the ringtone picker as a {@link Uri}.
165     * <p>
166     * It will be one of:
167     * <li> the picked ringtone,
168     * <li> a {@link Uri} that equals {@link System#DEFAULT_RINGTONE_URI},
169     * {@link System#DEFAULT_NOTIFICATION_URI}, or
170     * {@link System#DEFAULT_ALARM_ALERT_URI} if the default was chosen,
171     * <li> null if the "Silent" item was picked.
172     *
173     * @see #ACTION_RINGTONE_PICKER
174     */
175    public static final String EXTRA_RINGTONE_PICKED_URI =
176            "android.intent.extra.ringtone.PICKED_URI";
177
178    // Make sure the column ordering and then ..._COLUMN_INDEX are in sync
179
180    private static final String[] INTERNAL_COLUMNS = new String[] {
181        MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE,
182        "\"" + MediaStore.Audio.Media.INTERNAL_CONTENT_URI + "\"",
183        MediaStore.Audio.Media.TITLE_KEY
184    };
185
186    private static final String[] MEDIA_COLUMNS = new String[] {
187        MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE,
188        "\"" + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "\"",
189        MediaStore.Audio.Media.TITLE_KEY
190    };
191
192    /**
193     * The column index (in the cursor returned by {@link #getCursor()} for the
194     * row ID.
195     */
196    public static final int ID_COLUMN_INDEX = 0;
197
198    /**
199     * The column index (in the cursor returned by {@link #getCursor()} for the
200     * title.
201     */
202    public static final int TITLE_COLUMN_INDEX = 1;
203
204    /**
205     * The column index (in the cursor returned by {@link #getCursor()} for the
206     * media provider's URI.
207     */
208    public static final int URI_COLUMN_INDEX = 2;
209
210    private Activity mActivity;
211    private Context mContext;
212
213    private Cursor mCursor;
214
215    private int mType = TYPE_RINGTONE;
216
217    /**
218     * If a column (item from this list) exists in the Cursor, its value must
219     * be true (value of 1) for the row to be returned.
220     */
221    private final List<String> mFilterColumns = new ArrayList<String>();
222
223    private boolean mStopPreviousRingtone = true;
224    private Ringtone mPreviousRingtone;
225
226    /**
227     * Constructs a RingtoneManager. This constructor is recommended as its
228     * constructed instance manages cursor(s).
229     *
230     * @param activity The activity used to get a managed cursor.
231     */
232    public RingtoneManager(Activity activity) {
233        mContext = mActivity = activity;
234        setType(mType);
235    }
236
237    /**
238     * Constructs a RingtoneManager. The instance constructed by this
239     * constructor will not manage the cursor(s), so the client should handle
240     * this itself.
241     *
242     * @param context The context to used to get a cursor.
243     */
244    public RingtoneManager(Context context) {
245        mContext = context;
246        setType(mType);
247    }
248
249    /**
250     * Sets which type(s) of ringtones will be listed by this.
251     *
252     * @param type The type(s), one or more of {@link #TYPE_RINGTONE},
253     *            {@link #TYPE_NOTIFICATION}, {@link #TYPE_ALARM},
254     *            {@link #TYPE_ALL}.
255     * @see #EXTRA_RINGTONE_TYPE
256     */
257    public void setType(int type) {
258
259        if (mCursor != null) {
260            throw new IllegalStateException(
261                    "Setting filter columns should be done before querying for ringtones.");
262        }
263
264        mType = type;
265        setFilterColumnsList(type);
266    }
267
268    /**
269     * Infers the playback stream type based on what type of ringtones this
270     * manager is returning.
271     *
272     * @return The stream type.
273     */
274    public int inferStreamType() {
275        switch (mType) {
276
277            case TYPE_ALARM:
278                return AudioManager.STREAM_ALARM;
279
280            case TYPE_NOTIFICATION:
281                return AudioManager.STREAM_NOTIFICATION;
282
283            default:
284                return AudioManager.STREAM_RING;
285        }
286    }
287
288    /**
289     * Whether retrieving another {@link Ringtone} will stop playing the
290     * previously retrieved {@link Ringtone}.
291     * <p>
292     * If this is false, make sure to {@link Ringtone#stop()} any previous
293     * ringtones to free resources.
294     *
295     * @param stopPreviousRingtone If true, the previously retrieved
296     *            {@link Ringtone} will be stopped.
297     */
298    public void setStopPreviousRingtone(boolean stopPreviousRingtone) {
299        mStopPreviousRingtone = stopPreviousRingtone;
300    }
301
302    /**
303     * @see #setStopPreviousRingtone(boolean)
304     */
305    public boolean getStopPreviousRingtone() {
306        return mStopPreviousRingtone;
307    }
308
309    /**
310     * Stops playing the last {@link Ringtone} retrieved from this.
311     */
312    public void stopPreviousRingtone() {
313        if (mPreviousRingtone != null) {
314            mPreviousRingtone.stop();
315        }
316    }
317
318    /**
319     * Returns whether DRM ringtones will be included.
320     *
321     * @return Whether DRM ringtones will be included.
322     * @see #setIncludeDrm(boolean)
323     * Obsolete - always returns false
324     * @deprecated DRM ringtones are no longer supported
325     */
326    @Deprecated
327    public boolean getIncludeDrm() {
328        return false;
329    }
330
331    /**
332     * Sets whether to include DRM ringtones.
333     *
334     * @param includeDrm Whether to include DRM ringtones.
335     * Obsolete - no longer has any effect
336     * @deprecated DRM ringtones are no longer supported
337     */
338    @Deprecated
339    public void setIncludeDrm(boolean includeDrm) {
340        if (includeDrm) {
341            Log.w(TAG, "setIncludeDrm no longer supported");
342        }
343    }
344
345    /**
346     * Returns a {@link Cursor} of all the ringtones available. The returned
347     * cursor will be the same cursor returned each time this method is called,
348     * so do not {@link Cursor#close()} the cursor. The cursor can be
349     * {@link Cursor#deactivate()} safely.
350     * <p>
351     * If {@link RingtoneManager#RingtoneManager(Activity)} was not used, the
352     * caller should manage the returned cursor through its activity's life
353     * cycle to prevent leaking the cursor.
354     *
355     * @return A {@link Cursor} of all the ringtones available.
356     * @see #ID_COLUMN_INDEX
357     * @see #TITLE_COLUMN_INDEX
358     * @see #URI_COLUMN_INDEX
359     */
360    public Cursor getCursor() {
361        if (mCursor != null && mCursor.requery()) {
362            return mCursor;
363        }
364
365        final Cursor internalCursor = getInternalRingtones();
366        final Cursor mediaCursor = getMediaRingtones();
367
368        return mCursor = new SortCursor(new Cursor[] { internalCursor, mediaCursor },
369                MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
370    }
371
372    /**
373     * Gets a {@link Ringtone} for the ringtone at the given position in the
374     * {@link Cursor}.
375     *
376     * @param position The position (in the {@link Cursor}) of the ringtone.
377     * @return A {@link Ringtone} pointing to the ringtone.
378     */
379    public Ringtone getRingtone(int position) {
380        if (mStopPreviousRingtone && mPreviousRingtone != null) {
381            mPreviousRingtone.stop();
382        }
383
384        mPreviousRingtone = getRingtone(mContext, getRingtoneUri(position), inferStreamType());
385        return mPreviousRingtone;
386    }
387
388    /**
389     * Gets a {@link Uri} for the ringtone at the given position in the {@link Cursor}.
390     *
391     * @param position The position (in the {@link Cursor}) of the ringtone.
392     * @return A {@link Uri} pointing to the ringtone.
393     */
394    public Uri getRingtoneUri(int position) {
395        // use cursor directly instead of requerying it, which could easily
396        // cause position to shuffle.
397        if (mCursor == null || !mCursor.moveToPosition(position)) {
398            return null;
399        }
400
401        return getUriFromCursor(mCursor);
402    }
403
404    private static Uri getUriFromCursor(Cursor cursor) {
405        return ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), cursor
406                .getLong(ID_COLUMN_INDEX));
407    }
408
409    /**
410     * Gets the position of a {@link Uri} within this {@link RingtoneManager}.
411     *
412     * @param ringtoneUri The {@link Uri} to retreive the position of.
413     * @return The position of the {@link Uri}, or -1 if it cannot be found.
414     */
415    public int getRingtonePosition(Uri ringtoneUri) {
416
417        if (ringtoneUri == null) return -1;
418
419        final Cursor cursor = getCursor();
420        final int cursorCount = cursor.getCount();
421
422        if (!cursor.moveToFirst()) {
423            return -1;
424        }
425
426        // Only create Uri objects when the actual URI changes
427        Uri currentUri = null;
428        String previousUriString = null;
429        for (int i = 0; i < cursorCount; i++) {
430            String uriString = cursor.getString(URI_COLUMN_INDEX);
431            if (currentUri == null || !uriString.equals(previousUriString)) {
432                currentUri = Uri.parse(uriString);
433            }
434
435            if (ringtoneUri.equals(ContentUris.withAppendedId(currentUri, cursor
436                    .getLong(ID_COLUMN_INDEX)))) {
437                return i;
438            }
439
440            cursor.move(1);
441
442            previousUriString = uriString;
443        }
444
445        return -1;
446    }
447
448    /**
449     * Returns a valid ringtone URI. No guarantees on which it returns. If it
450     * cannot find one, returns null.
451     *
452     * @param context The context to use for querying.
453     * @return A ringtone URI, or null if one cannot be found.
454     */
455    public static Uri getValidRingtoneUri(Context context) {
456        final RingtoneManager rm = new RingtoneManager(context);
457
458        Uri uri = getValidRingtoneUriFromCursorAndClose(context, rm.getInternalRingtones());
459
460        if (uri == null) {
461            uri = getValidRingtoneUriFromCursorAndClose(context, rm.getMediaRingtones());
462        }
463
464        return uri;
465    }
466
467    private static Uri getValidRingtoneUriFromCursorAndClose(Context context, Cursor cursor) {
468        if (cursor != null) {
469            Uri uri = null;
470
471            if (cursor.moveToFirst()) {
472                uri = getUriFromCursor(cursor);
473            }
474            cursor.close();
475
476            return uri;
477        } else {
478            return null;
479        }
480    }
481
482    private Cursor getInternalRingtones() {
483        return query(
484                MediaStore.Audio.Media.INTERNAL_CONTENT_URI, INTERNAL_COLUMNS,
485                constructBooleanTrueWhereClause(mFilterColumns),
486                null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
487    }
488
489    private Cursor getMediaRingtones() {
490         // Get the external media cursor. First check to see if it is mounted.
491        final String status = Environment.getExternalStorageState();
492
493        return (status.equals(Environment.MEDIA_MOUNTED) ||
494                    status.equals(Environment.MEDIA_MOUNTED_READ_ONLY))
495                ? query(
496                    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MEDIA_COLUMNS,
497                    constructBooleanTrueWhereClause(mFilterColumns), null,
498                    MediaStore.Audio.Media.DEFAULT_SORT_ORDER)
499                : null;
500    }
501
502    private void setFilterColumnsList(int type) {
503        List<String> columns = mFilterColumns;
504        columns.clear();
505
506        if ((type & TYPE_RINGTONE) != 0) {
507            columns.add(MediaStore.Audio.AudioColumns.IS_RINGTONE);
508        }
509
510        if ((type & TYPE_NOTIFICATION) != 0) {
511            columns.add(MediaStore.Audio.AudioColumns.IS_NOTIFICATION);
512        }
513
514        if ((type & TYPE_ALARM) != 0) {
515            columns.add(MediaStore.Audio.AudioColumns.IS_ALARM);
516        }
517    }
518
519    /**
520     * Constructs a where clause that consists of at least one column being 1
521     * (true). This is used to find all matching sounds for the given sound
522     * types (ringtone, notifications, etc.)
523     *
524     * @param columns The columns that must be true.
525     * @return The where clause.
526     */
527    private static String constructBooleanTrueWhereClause(List<String> columns) {
528
529        if (columns == null) return null;
530
531        StringBuilder sb = new StringBuilder();
532        sb.append("(");
533
534        for (int i = columns.size() - 1; i >= 0; i--) {
535            sb.append(columns.get(i)).append("=1 or ");
536        }
537
538        if (columns.size() > 0) {
539            // Remove last ' or '
540            sb.setLength(sb.length() - 4);
541        }
542
543        sb.append(")");
544
545        return sb.toString();
546    }
547
548    private Cursor query(Uri uri,
549            String[] projection,
550            String selection,
551            String[] selectionArgs,
552            String sortOrder) {
553        if (mActivity != null) {
554            return mActivity.managedQuery(uri, projection, selection, selectionArgs, sortOrder);
555        } else {
556            return mContext.getContentResolver().query(uri, projection, selection, selectionArgs,
557                    sortOrder);
558        }
559    }
560
561    /**
562     * Returns a {@link Ringtone} for a given sound URI.
563     * <p>
564     * If the given URI cannot be opened for any reason, this method will
565     * attempt to fallback on another sound. If it cannot find any, it will
566     * return null.
567     *
568     * @param context A context used to query.
569     * @param ringtoneUri The {@link Uri} of a sound or ringtone.
570     * @return A {@link Ringtone} for the given URI, or null.
571     */
572    public static Ringtone getRingtone(final Context context, Uri ringtoneUri) {
573        // Don't set the stream type
574        return getRingtone(context, ringtoneUri, -1);
575    }
576
577    /**
578     * Returns a {@link Ringtone} for a given sound URI on the given stream
579     * type. Normally, if you change the stream type on the returned
580     * {@link Ringtone}, it will re-create the {@link MediaPlayer}. This is just
581     * an optimized route to avoid that.
582     *
583     * @param streamType The stream type for the ringtone, or -1 if it should
584     *            not be set (and the default used instead).
585     * @see #getRingtone(Context, Uri)
586     */
587    private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType) {
588        try {
589            final Ringtone r = new Ringtone(context, true);
590            if (streamType >= 0) {
591                r.setStreamType(streamType);
592            }
593            r.setUri(ringtoneUri);
594            return r;
595        } catch (Exception ex) {
596            Log.e(TAG, "Failed to open ringtone " + ringtoneUri + ": " + ex);
597        }
598
599        return null;
600    }
601
602    /**
603     * Gets the current default sound's {@link Uri}. This will give the actual
604     * sound {@link Uri}, instead of using this, most clients can use
605     * {@link System#DEFAULT_RINGTONE_URI}.
606     *
607     * @param context A context used for querying.
608     * @param type The type whose default sound should be returned. One of
609     *            {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
610     *            {@link #TYPE_ALARM}.
611     * @return A {@link Uri} pointing to the default sound for the sound type.
612     * @see #setActualDefaultRingtoneUri(Context, int, Uri)
613     */
614    public static Uri getActualDefaultRingtoneUri(Context context, int type) {
615        String setting = getSettingForType(type);
616        if (setting == null) return null;
617        final String uriString = Settings.System.getString(context.getContentResolver(), setting);
618        return uriString != null ? Uri.parse(uriString) : null;
619    }
620
621    /**
622     * Sets the {@link Uri} of the default sound for a given sound type.
623     *
624     * @param context A context used for querying.
625     * @param type The type whose default sound should be set. One of
626     *            {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
627     *            {@link #TYPE_ALARM}.
628     * @param ringtoneUri A {@link Uri} pointing to the default sound to set.
629     * @see #getActualDefaultRingtoneUri(Context, int)
630     */
631    public static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri) {
632        String setting = getSettingForType(type);
633        if (setting == null) return;
634        Settings.System.putString(context.getContentResolver(), setting,
635                ringtoneUri != null ? ringtoneUri.toString() : null);
636    }
637
638    private static String getSettingForType(int type) {
639        if ((type & TYPE_RINGTONE) != 0) {
640            return Settings.System.RINGTONE;
641        } else if ((type & TYPE_NOTIFICATION) != 0) {
642            return Settings.System.NOTIFICATION_SOUND;
643        } else if ((type & TYPE_ALARM) != 0) {
644            return Settings.System.ALARM_ALERT;
645        } else {
646            return null;
647        }
648    }
649
650    /**
651     * Returns whether the given {@link Uri} is one of the default ringtones.
652     *
653     * @param ringtoneUri The ringtone {@link Uri} to be checked.
654     * @return Whether the {@link Uri} is a default.
655     */
656    public static boolean isDefault(Uri ringtoneUri) {
657        return getDefaultType(ringtoneUri) != -1;
658    }
659
660    /**
661     * Returns the type of a default {@link Uri}.
662     *
663     * @param defaultRingtoneUri The default {@link Uri}. For example,
664     *            {@link System#DEFAULT_RINGTONE_URI},
665     *            {@link System#DEFAULT_NOTIFICATION_URI}, or
666     *            {@link System#DEFAULT_ALARM_ALERT_URI}.
667     * @return The type of the defaultRingtoneUri, or -1.
668     */
669    public static int getDefaultType(Uri defaultRingtoneUri) {
670        if (defaultRingtoneUri == null) {
671            return -1;
672        } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_RINGTONE_URI)) {
673            return TYPE_RINGTONE;
674        } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_NOTIFICATION_URI)) {
675            return TYPE_NOTIFICATION;
676        } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_ALARM_ALERT_URI)) {
677            return TYPE_ALARM;
678        } else {
679            return -1;
680        }
681    }
682
683    /**
684     * Returns the {@link Uri} for the default ringtone of a particular type.
685     * Rather than returning the actual ringtone's sound {@link Uri}, this will
686     * return the symbolic {@link Uri} which will resolved to the actual sound
687     * when played.
688     *
689     * @param type The ringtone type whose default should be returned.
690     * @return The {@link Uri} of the default ringtone for the given type.
691     */
692    public static Uri getDefaultUri(int type) {
693        if ((type & TYPE_RINGTONE) != 0) {
694            return Settings.System.DEFAULT_RINGTONE_URI;
695        } else if ((type & TYPE_NOTIFICATION) != 0) {
696            return Settings.System.DEFAULT_NOTIFICATION_URI;
697        } else if ((type & TYPE_ALARM) != 0) {
698            return Settings.System.DEFAULT_ALARM_ALERT_URI;
699        } else {
700            return null;
701        }
702    }
703
704}
705