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