RingtoneManager.java revision 899725b05dd5c8c51f9f802d4f0a7190532ce0a5
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        MediaStore.Audio.Media.TITLE_KEY
181    };
182
183    private static final String[] DRM_COLUMNS = new String[] {
184        DrmStore.Audio._ID, DrmStore.Audio.TITLE,
185        "\"" + DrmStore.Audio.CONTENT_URI + "\"",
186        DrmStore.Audio.TITLE + " AS " + MediaStore.Audio.Media.TITLE_KEY
187    };
188
189    private static final String[] MEDIA_COLUMNS = new String[] {
190        MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE,
191        "\"" + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "\"",
192        MediaStore.Audio.Media.TITLE_KEY
193    };
194
195    /**
196     * The column index (in the cursor returned by {@link #getCursor()} for the
197     * row ID.
198     */
199    public static final int ID_COLUMN_INDEX = 0;
200
201    /**
202     * The column index (in the cursor returned by {@link #getCursor()} for the
203     * title.
204     */
205    public static final int TITLE_COLUMN_INDEX = 1;
206
207    /**
208     * The column index (in the cursor returned by {@link #getCursor()} for the
209     * media provider's URI.
210     */
211    public static final int URI_COLUMN_INDEX = 2;
212
213    private Activity mActivity;
214    private Context mContext;
215
216    private Cursor mCursor;
217
218    private int mType = TYPE_RINGTONE;
219
220    /**
221     * If a column (item from this list) exists in the Cursor, its value must
222     * be true (value of 1) for the row to be returned.
223     */
224    private List<String> mFilterColumns = new ArrayList<String>();
225
226    private boolean mStopPreviousRingtone = true;
227    private Ringtone mPreviousRingtone;
228
229    private boolean mIncludeDrm;
230
231    /**
232     * Constructs a RingtoneManager. This constructor is recommended as its
233     * constructed instance manages cursor(s).
234     *
235     * @param activity The activity used to get a managed cursor.
236     */
237    public RingtoneManager(Activity activity) {
238        mContext = mActivity = activity;
239        setType(mType);
240    }
241
242    /**
243     * Constructs a RingtoneManager. The instance constructed by this
244     * constructor will not manage the cursor(s), so the client should handle
245     * this itself.
246     *
247     * @param context The context to used to get a cursor.
248     */
249    public RingtoneManager(Context context) {
250        mContext = context;
251        setType(mType);
252    }
253
254    /**
255     * Sets which type(s) of ringtones will be listed by this.
256     *
257     * @param type The type(s), one or more of {@link #TYPE_RINGTONE},
258     *            {@link #TYPE_NOTIFICATION}, {@link #TYPE_ALARM},
259     *            {@link #TYPE_ALL}.
260     * @see #EXTRA_RINGTONE_TYPE
261     */
262    public void setType(int type) {
263
264        if (mCursor != null) {
265            throw new IllegalStateException(
266                    "Setting filter columns should be done before querying for ringtones.");
267        }
268
269        mType = type;
270        setFilterColumnsList(type);
271    }
272
273    /**
274     * Infers the playback stream type based on what type of ringtones this
275     * manager is returning.
276     *
277     * @return The stream type.
278     */
279    public int inferStreamType() {
280        switch (mType) {
281
282            case TYPE_ALARM:
283                return AudioManager.STREAM_ALARM;
284
285            case TYPE_NOTIFICATION:
286                return AudioManager.STREAM_NOTIFICATION;
287
288            default:
289                return AudioManager.STREAM_RING;
290        }
291    }
292
293    /**
294     * Whether retrieving another {@link Ringtone} will stop playing the
295     * previously retrieved {@link Ringtone}.
296     * <p>
297     * If this is false, make sure to {@link Ringtone#stop()} any previous
298     * ringtones to free resources.
299     *
300     * @param stopPreviousRingtone If true, the previously retrieved
301     *            {@link Ringtone} will be stopped.
302     */
303    public void setStopPreviousRingtone(boolean stopPreviousRingtone) {
304        mStopPreviousRingtone = stopPreviousRingtone;
305    }
306
307    /**
308     * @see #setStopPreviousRingtone(boolean)
309     */
310    public boolean getStopPreviousRingtone() {
311        return mStopPreviousRingtone;
312    }
313
314    /**
315     * Stops playing the last {@link Ringtone} retrieved from this.
316     */
317    public void stopPreviousRingtone() {
318        if (mPreviousRingtone != null) {
319            mPreviousRingtone.stop();
320        }
321    }
322
323    /**
324     * Returns whether DRM ringtones will be included.
325     *
326     * @return Whether DRM ringtones will be included.
327     * @see #setIncludeDrm(boolean)
328     */
329    public boolean getIncludeDrm() {
330        return mIncludeDrm;
331    }
332
333    /**
334     * Sets whether to include DRM ringtones.
335     *
336     * @param includeDrm Whether to include DRM ringtones.
337     */
338    public void setIncludeDrm(boolean includeDrm) {
339        mIncludeDrm = includeDrm;
340    }
341
342    /**
343     * Returns a {@link Cursor} of all the ringtones available. The returned
344     * cursor will be the same cursor returned each time this method is called,
345     * so do not {@link Cursor#close()} the cursor. The cursor can be
346     * {@link Cursor#deactivate()} safely.
347     * <p>
348     * If {@link RingtoneManager#RingtoneManager(Activity)} was not used, the
349     * caller should manage the returned cursor through its activity's life
350     * cycle to prevent leaking the cursor.
351     *
352     * @return A {@link Cursor} of all the ringtones available.
353     * @see #ID_COLUMN_INDEX
354     * @see #TITLE_COLUMN_INDEX
355     * @see #URI_COLUMN_INDEX
356     */
357    public Cursor getCursor() {
358        if (mCursor != null && mCursor.requery()) {
359            return mCursor;
360        }
361
362        final Cursor internalCursor = getInternalRingtones();
363        final Cursor drmCursor = mIncludeDrm ? getDrmRingtones() : null;
364        final Cursor mediaCursor = getMediaRingtones();
365
366        return mCursor = new SortCursor(new Cursor[] { internalCursor, drmCursor, mediaCursor },
367                MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
368    }
369
370    /**
371     * Gets a {@link Ringtone} for the ringtone at the given position in the
372     * {@link Cursor}.
373     *
374     * @param position The position (in the {@link Cursor}) of the ringtone.
375     * @return A {@link Ringtone} pointing to the ringtone.
376     */
377    public Ringtone getRingtone(int position) {
378        if (mStopPreviousRingtone && mPreviousRingtone != null) {
379            mPreviousRingtone.stop();
380        }
381
382        mPreviousRingtone = getRingtone(mContext, getRingtoneUri(position), inferStreamType());
383        return mPreviousRingtone;
384    }
385
386    /**
387     * Gets a {@link Uri} for the ringtone at the given position in the {@link Cursor}.
388     *
389     * @param position The position (in the {@link Cursor}) of the ringtone.
390     * @return A {@link Uri} pointing to the ringtone.
391     */
392    public Uri getRingtoneUri(int position) {
393        final Cursor cursor = getCursor();
394
395        if (!cursor.moveToPosition(position)) {
396            return null;
397        }
398
399        return getUriFromCursor(cursor);
400    }
401
402    private static Uri getUriFromCursor(Cursor cursor) {
403        return ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), cursor
404                .getLong(ID_COLUMN_INDEX));
405    }
406
407    /**
408     * Gets the position of a {@link Uri} within this {@link RingtoneManager}.
409     *
410     * @param ringtoneUri The {@link Uri} to retreive the position of.
411     * @return The position of the {@link Uri}, or -1 if it cannot be found.
412     */
413    public int getRingtonePosition(Uri ringtoneUri) {
414
415        if (ringtoneUri == null) return -1;
416
417        final Cursor cursor = getCursor();
418        final int cursorCount = cursor.getCount();
419
420        if (!cursor.moveToFirst()) {
421            return -1;
422        }
423
424        // Only create Uri objects when the actual URI changes
425        Uri currentUri = null;
426        String previousUriString = null;
427        for (int i = 0; i < cursorCount; i++) {
428            String uriString = cursor.getString(URI_COLUMN_INDEX);
429            if (currentUri == null || !uriString.equals(previousUriString)) {
430                currentUri = Uri.parse(uriString);
431            }
432
433            if (ringtoneUri.equals(ContentUris.withAppendedId(currentUri, cursor
434                    .getLong(ID_COLUMN_INDEX)))) {
435                return i;
436            }
437
438            cursor.move(1);
439
440            previousUriString = uriString;
441        }
442
443        return -1;
444    }
445
446    /**
447     * Returns a valid ringtone URI. No guarantees on which it returns. If it
448     * cannot find one, returns null.
449     *
450     * @param context The context to use for querying.
451     * @return A ringtone URI, or null if one cannot be found.
452     */
453    public static Uri getValidRingtoneUri(Context context) {
454        final RingtoneManager rm = new RingtoneManager(context);
455
456        Uri uri = getValidRingtoneUriFromCursorAndClose(context, rm.getInternalRingtones());
457
458        if (uri == null) {
459            uri = getValidRingtoneUriFromCursorAndClose(context, rm.getMediaRingtones());
460        }
461
462        if (uri == null) {
463            uri = getValidRingtoneUriFromCursorAndClose(context, rm.getDrmRingtones());
464        }
465
466        return uri;
467    }
468
469    private static Uri getValidRingtoneUriFromCursorAndClose(Context context, Cursor cursor) {
470        if (cursor != null) {
471            Uri uri = null;
472
473            if (cursor.moveToFirst()) {
474                uri = getUriFromCursor(cursor);
475            }
476            cursor.close();
477
478            return uri;
479        } else {
480            return null;
481        }
482    }
483
484    private Cursor getInternalRingtones() {
485        return query(
486                MediaStore.Audio.Media.INTERNAL_CONTENT_URI, INTERNAL_COLUMNS,
487                constructBooleanTrueWhereClause(mFilterColumns),
488                null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
489    }
490
491    private Cursor getDrmRingtones() {
492        // DRM store does not have any columns to use for filtering
493        return query(
494                DrmStore.Audio.CONTENT_URI, DRM_COLUMNS,
495                null, null, DrmStore.Audio.TITLE);
496    }
497
498    private Cursor getMediaRingtones() {
499         // Get the external media cursor. First check to see if it is mounted.
500        final String status = Environment.getExternalStorageState();
501
502        return (status.equals(Environment.MEDIA_MOUNTED) ||
503                    status.equals(Environment.MEDIA_MOUNTED_READ_ONLY))
504                ? query(
505                    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MEDIA_COLUMNS,
506                    constructBooleanTrueWhereClause(mFilterColumns), null,
507                    MediaStore.Audio.Media.DEFAULT_SORT_ORDER)
508                : null;
509    }
510
511    private void setFilterColumnsList(int type) {
512        List<String> columns = mFilterColumns;
513        columns.clear();
514
515        if ((type & TYPE_RINGTONE) != 0) {
516            columns.add(MediaStore.Audio.AudioColumns.IS_RINGTONE);
517        }
518
519        if ((type & TYPE_NOTIFICATION) != 0) {
520            columns.add(MediaStore.Audio.AudioColumns.IS_NOTIFICATION);
521        }
522
523        if ((type & TYPE_ALARM) != 0) {
524            columns.add(MediaStore.Audio.AudioColumns.IS_ALARM);
525        }
526    }
527
528    /**
529     * Constructs a where clause that consists of at least one column being 1
530     * (true). This is used to find all matching sounds for the given sound
531     * types (ringtone, notifications, etc.)
532     *
533     * @param columns The columns that must be true.
534     * @return The where clause.
535     */
536    private static String constructBooleanTrueWhereClause(List<String> columns) {
537
538        if (columns == null) return null;
539
540        StringBuilder sb = new StringBuilder();
541        for (int i = columns.size() - 1; i >= 0; i--) {
542            sb.append(columns.get(i)).append("=1 or ");
543        }
544
545        if (columns.size() > 0) {
546            // Remove last ' or '
547            sb.setLength(sb.length() - 4);
548        }
549
550        return sb.toString();
551    }
552
553    private Cursor query(Uri uri,
554            String[] projection,
555            String selection,
556            String[] selectionArgs,
557            String sortOrder) {
558        if (mActivity != null) {
559            return mActivity.managedQuery(uri, projection, selection, selectionArgs, sortOrder);
560        } else {
561            return mContext.getContentResolver().query(uri, projection, selection, selectionArgs,
562                    sortOrder);
563        }
564    }
565
566    /**
567     * Returns a {@link Ringtone} for a given sound URI.
568     * <p>
569     * If the given URI cannot be opened for any reason, this method will
570     * attempt to fallback on another sound. If it cannot find any, it will
571     * return null.
572     *
573     * @param context A context used to query.
574     * @param ringtoneUri The {@link Uri} of a sound or ringtone.
575     * @return A {@link Ringtone} for the given URI, or null.
576     */
577    public static Ringtone getRingtone(final Context context, Uri ringtoneUri) {
578        // Don't set the stream type
579        return getRingtone(context, ringtoneUri, -1);
580    }
581
582    /**
583     * Returns a {@link Ringtone} for a given sound URI on the given stream
584     * type. Normally, if you change the stream type on the returned
585     * {@link Ringtone}, it will re-create the {@link MediaPlayer}. This is just
586     * an optimized route to avoid that.
587     *
588     * @param streamType The stream type for the ringtone, or -1 if it should
589     *            not be set (and the default used instead).
590     * @see #getRingtone(Context, Uri)
591     */
592    private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType) {
593
594        try {
595            Ringtone r = new Ringtone(context);
596            if (streamType >= 0) {
597                r.setStreamType(streamType);
598            }
599            r.open(ringtoneUri);
600            return r;
601        } catch (Exception ex) {
602            Log.e(TAG, "Failed to open ringtone " + ringtoneUri);
603        }
604
605        // Ringtone doesn't exist, use the fallback ringtone.
606        try {
607            AssetFileDescriptor afd = context.getResources().openRawResourceFd(
608                    com.android.internal.R.raw.fallbackring);
609            if (afd != null) {
610                Ringtone r = new Ringtone(context);
611                r.open(afd);
612                afd.close();
613                return r;
614            }
615        } catch (Exception ex) {
616        }
617
618        // we should never get here
619        Log.e(TAG, "unable to find a usable ringtone");
620        return null;
621    }
622
623    /**
624     * Gets the current default sound's {@link Uri}. This will give the actual
625     * sound {@link Uri}, instead of using this, most clients can use
626     * {@link System#DEFAULT_RINGTONE_URI}.
627     *
628     * @param context A context used for querying.
629     * @param type The type whose default sound should be returned. One of
630     *            {@link #TYPE_RINGTONE} or {@link #TYPE_NOTIFICATION}.
631     * @return A {@link Uri} pointing to the default sound for the sound type.
632     * @see #setActualDefaultRingtoneUri(Context, int, Uri)
633     */
634    public static Uri getActualDefaultRingtoneUri(Context context, int type) {
635        String setting = getSettingForType(type);
636        if (setting == null) return null;
637        final String uriString = Settings.System.getString(context.getContentResolver(), setting);
638        return uriString != null ? Uri.parse(uriString) : getValidRingtoneUri(context);
639    }
640
641    /**
642     * Sets the {@link Uri} of the default sound for a given sound type.
643     *
644     * @param context A context used for querying.
645     * @param type The type whose default sound should be set. One of
646     *            {@link #TYPE_RINGTONE} or {@link #TYPE_NOTIFICATION}.
647     * @param ringtoneUri A {@link Uri} pointing to the default sound to set.
648     * @see #getActualDefaultRingtoneUri(Context, int)
649     */
650    public static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri) {
651        String setting = getSettingForType(type);
652        if (setting == null) return;
653        Settings.System.putString(context.getContentResolver(), setting, ringtoneUri.toString());
654    }
655
656    private static String getSettingForType(int type) {
657        if ((type & TYPE_RINGTONE) != 0) {
658            return Settings.System.RINGTONE;
659        } else if ((type & TYPE_NOTIFICATION) != 0) {
660            return Settings.System.NOTIFICATION_SOUND;
661        } else {
662            return null;
663        }
664    }
665
666    /**
667     * Returns whether the given {@link Uri} is one of the default ringtones.
668     *
669     * @param ringtoneUri The ringtone {@link Uri} to be checked.
670     * @return Whether the {@link Uri} is a default.
671     */
672    public static boolean isDefault(Uri ringtoneUri) {
673        return getDefaultType(ringtoneUri) != -1;
674    }
675
676    /**
677     * Returns the type of a default {@link Uri}.
678     *
679     * @param defaultRingtoneUri The default {@link Uri}. For example,
680     *            {@link System#DEFAULT_RINGTONE_URI} or
681     *            {@link System#DEFAULT_NOTIFICATION_URI}.
682     * @return The type of the defaultRingtoneUri, or -1.
683     */
684    public static int getDefaultType(Uri defaultRingtoneUri) {
685        if (defaultRingtoneUri == null) {
686            return -1;
687        } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_RINGTONE_URI)) {
688            return TYPE_RINGTONE;
689        } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_NOTIFICATION_URI)) {
690            return TYPE_NOTIFICATION;
691        } else {
692            return -1;
693        }
694    }
695
696    /**
697     * Returns the {@link Uri} for the default ringtone of a particular type.
698     * Rather than returning the actual ringtone's sound {@link Uri}, this will
699     * return the symbolic {@link Uri} which will resolved to the actual sound
700     * when played.
701     *
702     * @param type The ringtone type whose default should be returned.
703     * @return The {@link Uri} of the default ringtone for the given type.
704     */
705    public static Uri getDefaultUri(int type) {
706        if ((type & TYPE_RINGTONE) != 0) {
707            return Settings.System.DEFAULT_RINGTONE_URI;
708        } else if ((type & TYPE_NOTIFICATION) != 0) {
709            return Settings.System.DEFAULT_NOTIFICATION_URI;
710        } else {
711            return null;
712        }
713    }
714
715}
716