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