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