MediaStore.java revision 816cf52abd8f45770f0ac922bbb819184ed4b90f
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.provider; 18 19import android.annotation.SdkConstant; 20import android.annotation.SdkConstant.SdkConstantType; 21import android.content.ContentResolver; 22import android.content.ContentValues; 23import android.content.ContentUris; 24import android.database.Cursor; 25import android.database.DatabaseUtils; 26import android.graphics.Bitmap; 27import android.graphics.BitmapFactory; 28import android.graphics.Matrix; 29import android.net.Uri; 30import android.os.Environment; 31import android.util.Log; 32 33import java.io.FileInputStream; 34import java.io.FileNotFoundException; 35import java.io.IOException; 36import java.io.InputStream; 37import java.io.OutputStream; 38import java.io.UnsupportedEncodingException; 39import java.text.Collator; 40 41/** 42 * The Media provider contains meta data for all available media on both internal 43 * and external storage devices. 44 */ 45public final class MediaStore 46{ 47 private final static String TAG = "MediaStore"; 48 49 public static final String AUTHORITY = "media"; 50 51 private static final String CONTENT_AUTHORITY_SLASH = "content://" + AUTHORITY + "/"; 52 53 /** 54 * Activity Action: Perform a search for media. 55 * Contains at least the {@link android.app.SearchManager#QUERY} extra. 56 * May also contain any combination of the following extras: 57 * EXTRA_MEDIA_ARTIST, EXTRA_MEDIA_ALBUM, EXTRA_MEDIA_TITLE, EXTRA_MEDIA_FOCUS 58 * 59 * @see android.provider.MediaStore#EXTRA_MEDIA_ARTIST 60 * @see android.provider.MediaStore#EXTRA_MEDIA_ALBUM 61 * @see android.provider.MediaStore#EXTRA_MEDIA_TITLE 62 * @see android.provider.MediaStore#EXTRA_MEDIA_FOCUS 63 */ 64 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 65 public static final String INTENT_ACTION_MEDIA_SEARCH = "android.intent.action.MEDIA_SEARCH"; 66 67 /** 68 * The name of the Intent-extra used to define the artist 69 */ 70 public static final String EXTRA_MEDIA_ARTIST = "android.intent.extra.artist"; 71 /** 72 * The name of the Intent-extra used to define the album 73 */ 74 public static final String EXTRA_MEDIA_ALBUM = "android.intent.extra.album"; 75 /** 76 * The name of the Intent-extra used to define the song title 77 */ 78 public static final String EXTRA_MEDIA_TITLE = "android.intent.extra.title"; 79 /** 80 * The name of the Intent-extra used to define the search focus. The search focus 81 * indicates whether the search should be for things related to the artist, album 82 * or song that is identified by the other extras. 83 */ 84 public static final String EXTRA_MEDIA_FOCUS = "android.intent.extra.focus"; 85 86 /** 87 * The name of the Intent-extra used to control the orientation of a ViewImage or a MovieView. 88 * This is an int property that overrides the activity's requestedOrientation. 89 * @see android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED 90 */ 91 public static final String EXTRA_SCREEN_ORIENTATION = "android.intent.extra.screenOrientation"; 92 93 /** 94 * The name of an Intent-extra used to control the UI of a ViewImage. 95 * This is a boolean property that overrides the activity's default fullscreen state. 96 * @hide 97 */ 98 public static final String EXTRA_FULL_SCREEN = "android.intent.extra.fullScreen"; 99 100 /** 101 * The name of an Intent-extra used to control the UI of a ViewImage. 102 * This is a boolean property that specifies whether or not to show action icons. 103 * @hide 104 */ 105 public static final String EXTRA_SHOW_ACTION_ICONS = "android.intent.extra.showActionIcons"; 106 107 /** 108 * The name of the Intent-extra used to control the onCompletion behavior of a MovieView. 109 * This is a boolean property that specifies whether or not to finish the MovieView activity 110 * when the movie completes playing. The default value is true, which means to automatically 111 * exit the movie player activity when the movie completes playing. 112 */ 113 public static final String EXTRA_FINISH_ON_COMPLETION = "android.intent.extra.finishOnCompletion"; 114 115 /** 116 * The name of the Intent action used to launch a camera in still image mode. 117 */ 118 public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA"; 119 120 /** 121 * The name of the Intent action used to launch a camera in video mode. 122 */ 123 public static final String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA"; 124 125 /** 126 * Standard Intent action that can be sent to have the camera application 127 * capture an image and return it. 128 * <p> 129 * The caller may pass an extra EXTRA_OUTPUT to control where this image will be written. 130 * If the EXTRA_OUTPUT is not present, then a small sized image is returned as a Bitmap 131 * object in the extra field. This is useful for applications that only need a small image. 132 * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri 133 * value of EXTRA_OUTPUT. 134 * @see #EXTRA_OUTPUT 135 * @see #EXTRA_VIDEO_QUALITY 136 */ 137 public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE"; 138 139 /** 140 * Standard Intent action that can be sent to have the camera application 141 * capture an video and return it. 142 * <p> 143 * The caller may pass in an extra EXTRA_VIDEO_QUALITY to control the video quality. 144 * <p> 145 * The caller may pass in an extra EXTRA_OUTPUT to control 146 * where the video is written. If EXTRA_OUTPUT is not present the video will be 147 * written to the standard location for videos, and the Uri of that location will be 148 * returned in the data field of the Uri. 149 * @see #EXTRA_OUTPUT 150 */ 151 public final static String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE"; 152 153 /** 154 * The name of the Intent-extra used to control the quality of a recorded video. This is an 155 * integer property. Currently value 0 means low quality, suitable for MMS messages, and 156 * value 1 means high quality. In the future other quality levels may be added. 157 */ 158 public final static String EXTRA_VIDEO_QUALITY = "android.intent.extra.videoQuality"; 159 160 /** 161 * Specify the maximum allowed size. 162 * @hide 163 */ 164 public final static String EXTRA_SIZE_LIMIT = "android.intent.extra.sizeLimit"; 165 166 /** 167 * The name of the Intent-extra used to indicate a content resolver Uri to be used to 168 * store the requested image or video. 169 */ 170 public final static String EXTRA_OUTPUT = "output"; 171 172 /** 173 * Common fields for most MediaProvider tables 174 */ 175 176 public interface MediaColumns extends BaseColumns { 177 /** 178 * The data stream for the file 179 * <P>Type: DATA STREAM</P> 180 */ 181 public static final String DATA = "_data"; 182 183 /** 184 * The size of the file in bytes 185 * <P>Type: INTEGER (long)</P> 186 */ 187 public static final String SIZE = "_size"; 188 189 /** 190 * The display name of the file 191 * <P>Type: TEXT</P> 192 */ 193 public static final String DISPLAY_NAME = "_display_name"; 194 195 /** 196 * The title of the content 197 * <P>Type: TEXT</P> 198 */ 199 public static final String TITLE = "title"; 200 201 /** 202 * The time the file was added to the media provider 203 * Units are seconds since 1970. 204 * <P>Type: INTEGER (long)</P> 205 */ 206 public static final String DATE_ADDED = "date_added"; 207 208 /** 209 * The time the file was last modified 210 * Units are seconds since 1970. 211 * NOTE: This is for internal use by the media scanner. Do not modify this field. 212 * <P>Type: INTEGER (long)</P> 213 */ 214 public static final String DATE_MODIFIED = "date_modified"; 215 216 /** 217 * The MIME type of the file 218 * <P>Type: TEXT</P> 219 */ 220 public static final String MIME_TYPE = "mime_type"; 221 } 222 223 /** 224 * Contains meta data for all available images. 225 */ 226 public static final class Images 227 { 228 public interface ImageColumns extends MediaColumns { 229 /** 230 * The description of the image 231 * <P>Type: TEXT</P> 232 */ 233 public static final String DESCRIPTION = "description"; 234 235 /** 236 * The picasa id of the image 237 * <P>Type: TEXT</P> 238 */ 239 public static final String PICASA_ID = "picasa_id"; 240 241 /** 242 * Whether the video should be published as public or private 243 * <P>Type: INTEGER</P> 244 */ 245 public static final String IS_PRIVATE = "isprivate"; 246 247 /** 248 * The latitude where the image was captured. 249 * <P>Type: DOUBLE</P> 250 */ 251 public static final String LATITUDE = "latitude"; 252 253 /** 254 * The longitude where the image was captured. 255 * <P>Type: DOUBLE</P> 256 */ 257 public static final String LONGITUDE = "longitude"; 258 259 /** 260 * The date & time that the image was taken in units 261 * of milliseconds since jan 1, 1970. 262 * <P>Type: INTEGER</P> 263 */ 264 public static final String DATE_TAKEN = "datetaken"; 265 266 /** 267 * The orientation for the image expressed as degrees. 268 * Only degrees 0, 90, 180, 270 will work. 269 * <P>Type: INTEGER</P> 270 */ 271 public static final String ORIENTATION = "orientation"; 272 273 /** 274 * The mini thumb id. 275 * <P>Type: INTEGER</P> 276 */ 277 public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; 278 279 /** 280 * The bucket id of the image. This is a read-only property that 281 * is automatically computed from the DATA column. 282 * <P>Type: TEXT</P> 283 */ 284 public static final String BUCKET_ID = "bucket_id"; 285 286 /** 287 * The bucket display name of the image. This is a read-only property that 288 * is automatically computed from the DATA column. 289 * <P>Type: TEXT</P> 290 */ 291 public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; 292 } 293 294 public static final class Media implements ImageColumns { 295 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) 296 { 297 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER); 298 } 299 300 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection, 301 String where, String orderBy) 302 { 303 return cr.query(uri, projection, where, 304 null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy); 305 } 306 307 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection, 308 String selection, String [] selectionArgs, String orderBy) 309 { 310 return cr.query(uri, projection, selection, 311 selectionArgs, orderBy == null ? DEFAULT_SORT_ORDER : orderBy); 312 } 313 314 /** 315 * Retrieves an image for the given url as a {@link Bitmap}. 316 * 317 * @param cr The content resolver to use 318 * @param url The url of the image 319 * @throws FileNotFoundException 320 * @throws IOException 321 */ 322 public static final Bitmap getBitmap(ContentResolver cr, Uri url) 323 throws FileNotFoundException, IOException 324 { 325 InputStream input = cr.openInputStream(url); 326 Bitmap bitmap = BitmapFactory.decodeStream(input); 327 input.close(); 328 return bitmap; 329 } 330 331 /** 332 * Insert an image and create a thumbnail for it. 333 * 334 * @param cr The content resolver to use 335 * @param imagePath The path to the image to insert 336 * @param name The name of the image 337 * @param description The description of the image 338 * @return The URL to the newly created image 339 * @throws FileNotFoundException 340 */ 341 public static final String insertImage(ContentResolver cr, String imagePath, String name, 342 String description) throws FileNotFoundException 343 { 344 // Check if file exists with a FileInputStream 345 FileInputStream stream = new FileInputStream(imagePath); 346 try { 347 Bitmap bm = BitmapFactory.decodeFile(imagePath); 348 String ret = insertImage(cr, bm, name, description); 349 bm.recycle(); 350 return ret; 351 } finally { 352 try { 353 stream.close(); 354 } catch (IOException e) { 355 } 356 } 357 } 358 359 private static final Bitmap StoreThumbnail( 360 ContentResolver cr, 361 Bitmap source, 362 long id, 363 float width, float height, 364 int kind) { 365 // create the matrix to scale it 366 Matrix matrix = new Matrix(); 367 368 float scaleX = width / source.getWidth(); 369 float scaleY = height / source.getHeight(); 370 371 matrix.setScale(scaleX, scaleY); 372 373 Bitmap thumb = Bitmap.createBitmap(source, 0, 0, 374 source.getWidth(), 375 source.getHeight(), matrix, 376 true); 377 378 ContentValues values = new ContentValues(4); 379 values.put(Images.Thumbnails.KIND, kind); 380 values.put(Images.Thumbnails.IMAGE_ID, (int)id); 381 values.put(Images.Thumbnails.HEIGHT, thumb.getHeight()); 382 values.put(Images.Thumbnails.WIDTH, thumb.getWidth()); 383 384 Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values); 385 386 try { 387 OutputStream thumbOut = cr.openOutputStream(url); 388 389 thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut); 390 thumbOut.close(); 391 return thumb; 392 } 393 catch (FileNotFoundException ex) { 394 return null; 395 } 396 catch (IOException ex) { 397 return null; 398 } 399 } 400 401 /** 402 * Insert an image and create a thumbnail for it. 403 * 404 * @param cr The content resolver to use 405 * @param source The stream to use for the image 406 * @param title The name of the image 407 * @param description The description of the image 408 * @return The URL to the newly created image, or <code>null</code> if the image failed to be stored 409 * for any reason. 410 */ 411 public static final String insertImage(ContentResolver cr, Bitmap source, 412 String title, String description) 413 { 414 ContentValues values = new ContentValues(); 415 values.put(Images.Media.TITLE, title); 416 values.put(Images.Media.DESCRIPTION, description); 417 values.put(Images.Media.MIME_TYPE, "image/jpeg"); 418 419 Uri url = null; 420 String stringUrl = null; /* value to be returned */ 421 422 try 423 { 424 url = cr.insert(EXTERNAL_CONTENT_URI, values); 425 426 if (source != null) { 427 OutputStream imageOut = cr.openOutputStream(url); 428 try { 429 source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut); 430 } finally { 431 imageOut.close(); 432 } 433 434 long id = ContentUris.parseId(url); 435 Bitmap miniThumb = StoreThumbnail(cr, source, id, 320F, 240F, Images.Thumbnails.MINI_KIND); 436 Bitmap microThumb = StoreThumbnail(cr, miniThumb, id, 50F, 50F, Images.Thumbnails.MICRO_KIND); 437 } else { 438 Log.e(TAG, "Failed to create thumbnail, removing original"); 439 cr.delete(url, null, null); 440 url = null; 441 } 442 } catch (Exception e) { 443 Log.e(TAG, "Failed to insert image", e); 444 if (url != null) { 445 cr.delete(url, null, null); 446 url = null; 447 } 448 } 449 450 if (url != null) { 451 stringUrl = url.toString(); 452 } 453 454 return stringUrl; 455 } 456 457 /** 458 * Get the content:// style URI for the image media table on the 459 * given volume. 460 * 461 * @param volumeName the name of the volume to get the URI for 462 * @return the URI to the image media table on the given volume 463 */ 464 public static Uri getContentUri(String volumeName) { 465 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 466 "/images/media"); 467 } 468 469 /** 470 * The content:// style URI for the internal storage. 471 */ 472 public static final Uri INTERNAL_CONTENT_URI = 473 getContentUri("internal"); 474 475 /** 476 * The content:// style URI for the "primary" external storage 477 * volume. 478 */ 479 public static final Uri EXTERNAL_CONTENT_URI = 480 getContentUri("external"); 481 482 /** 483 * The MIME type of of this directory of 484 * images. Note that each entry in this directory will have a standard 485 * image MIME type as appropriate -- for example, image/jpeg. 486 */ 487 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/image"; 488 489 /** 490 * The default sort order for this table 491 */ 492 public static final String DEFAULT_SORT_ORDER = ImageColumns.BUCKET_DISPLAY_NAME; 493 } 494 495 public static class Thumbnails implements BaseColumns 496 { 497 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) 498 { 499 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER); 500 } 501 502 public static final Cursor queryMiniThumbnails(ContentResolver cr, Uri uri, int kind, String[] projection) 503 { 504 return cr.query(uri, projection, "kind = " + kind, null, DEFAULT_SORT_ORDER); 505 } 506 507 public static final Cursor queryMiniThumbnail(ContentResolver cr, long origId, int kind, String[] projection) 508 { 509 return cr.query(EXTERNAL_CONTENT_URI, projection, 510 IMAGE_ID + " = " + origId + " AND " + KIND + " = " + 511 kind, null, null); 512 } 513 514 /** 515 * Get the content:// style URI for the image media table on the 516 * given volume. 517 * 518 * @param volumeName the name of the volume to get the URI for 519 * @return the URI to the image media table on the given volume 520 */ 521 public static Uri getContentUri(String volumeName) { 522 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 523 "/images/thumbnails"); 524 } 525 526 /** 527 * The content:// style URI for the internal storage. 528 */ 529 public static final Uri INTERNAL_CONTENT_URI = 530 getContentUri("internal"); 531 532 /** 533 * The content:// style URI for the "primary" external storage 534 * volume. 535 */ 536 public static final Uri EXTERNAL_CONTENT_URI = 537 getContentUri("external"); 538 539 /** 540 * The default sort order for this table 541 */ 542 public static final String DEFAULT_SORT_ORDER = "image_id ASC"; 543 544 /** 545 * The data stream for the thumbnail 546 * <P>Type: DATA STREAM</P> 547 */ 548 public static final String DATA = "_data"; 549 550 /** 551 * The original image for the thumbnal 552 * <P>Type: INTEGER (ID from Images table)</P> 553 */ 554 public static final String IMAGE_ID = "image_id"; 555 556 /** 557 * The kind of the thumbnail 558 * <P>Type: INTEGER (One of the values below)</P> 559 */ 560 public static final String KIND = "kind"; 561 562 public static final int MINI_KIND = 1; 563 public static final int FULL_SCREEN_KIND = 2; 564 public static final int MICRO_KIND = 3; 565 566 /** 567 * The width of the thumbnal 568 * <P>Type: INTEGER (long)</P> 569 */ 570 public static final String WIDTH = "width"; 571 572 /** 573 * The height of the thumbnail 574 * <P>Type: INTEGER (long)</P> 575 */ 576 public static final String HEIGHT = "height"; 577 } 578 } 579 580 /** 581 * Container for all audio content. 582 */ 583 public static final class Audio { 584 /** 585 * Columns for audio file that show up in multiple tables. 586 */ 587 public interface AudioColumns extends MediaColumns { 588 589 /** 590 * A non human readable key calculated from the TITLE, used for 591 * searching, sorting and grouping 592 * <P>Type: TEXT</P> 593 */ 594 public static final String TITLE_KEY = "title_key"; 595 596 /** 597 * The duration of the audio file, in ms 598 * <P>Type: INTEGER (long)</P> 599 */ 600 public static final String DURATION = "duration"; 601 602 /** 603 * The position, in ms, playback was at when playback for this file 604 * was last stopped. 605 * <P>Type: INTEGER (long)</P> 606 * @hide 607 */ 608 public static final String BOOKMARK = "bookmark"; 609 610 /** 611 * The id of the artist who created the audio file, if any 612 * <P>Type: INTEGER (long)</P> 613 */ 614 public static final String ARTIST_ID = "artist_id"; 615 616 /** 617 * The artist who created the audio file, if any 618 * <P>Type: TEXT</P> 619 */ 620 public static final String ARTIST = "artist"; 621 622 /** 623 * A non human readable key calculated from the ARTIST, used for 624 * searching, sorting and grouping 625 * <P>Type: TEXT</P> 626 */ 627 public static final String ARTIST_KEY = "artist_key"; 628 629 /** 630 * The composer of the audio file, if any 631 * <P>Type: TEXT</P> 632 */ 633 public static final String COMPOSER = "composer"; 634 635 /** 636 * The id of the album the audio file is from, if any 637 * <P>Type: INTEGER (long)</P> 638 */ 639 public static final String ALBUM_ID = "album_id"; 640 641 /** 642 * The album the audio file is from, if any 643 * <P>Type: TEXT</P> 644 */ 645 public static final String ALBUM = "album"; 646 647 /** 648 * A non human readable key calculated from the ALBUM, used for 649 * searching, sorting and grouping 650 * <P>Type: TEXT</P> 651 */ 652 public static final String ALBUM_KEY = "album_key"; 653 654 /** 655 * A URI to the album art, if any 656 * <P>Type: TEXT</P> 657 */ 658 public static final String ALBUM_ART = "album_art"; 659 660 /** 661 * The track number of this song on the album, if any. 662 * This number encodes both the track number and the 663 * disc number. For multi-disc sets, this number will 664 * be 1xxx for tracks on the first disc, 2xxx for tracks 665 * on the second disc, etc. 666 * <P>Type: INTEGER</P> 667 */ 668 public static final String TRACK = "track"; 669 670 /** 671 * The year the audio file was recorded, if any 672 * <P>Type: INTEGER</P> 673 */ 674 public static final String YEAR = "year"; 675 676 /** 677 * Non-zero if the audio file is music 678 * <P>Type: INTEGER (boolean)</P> 679 */ 680 public static final String IS_MUSIC = "is_music"; 681 682 /** 683 * Non-zero if the audio file is a podcast 684 * <P>Type: INTEGER (boolean)</P> 685 * @hide 686 */ 687 public static final String IS_PODCAST = "is_podcast"; 688 689 /** 690 * Non-zero id the audio file may be a ringtone 691 * <P>Type: INTEGER (boolean)</P> 692 */ 693 public static final String IS_RINGTONE = "is_ringtone"; 694 695 /** 696 * Non-zero id the audio file may be an alarm 697 * <P>Type: INTEGER (boolean)</P> 698 */ 699 public static final String IS_ALARM = "is_alarm"; 700 701 /** 702 * Non-zero id the audio file may be a notification sound 703 * <P>Type: INTEGER (boolean)</P> 704 */ 705 public static final String IS_NOTIFICATION = "is_notification"; 706 } 707 708 /** 709 * Converts a name to a "key" that can be used for grouping, sorting 710 * and searching. 711 * The rules that govern this conversion are: 712 * - remove 'special' characters like ()[]'!?., 713 * - remove leading/trailing spaces 714 * - convert everything to lowercase 715 * - remove leading "the ", "an " and "a " 716 * - remove trailing ", the|an|a" 717 * - remove accents. This step leaves us with CollationKey data, 718 * which is not human readable 719 * 720 * @param name The artist or album name to convert 721 * @return The "key" for the given name. 722 */ 723 public static String keyFor(String name) { 724 if (name != null) { 725 boolean sortfirst = false; 726 if (name.equals(android.media.MediaFile.UNKNOWN_STRING)) { 727 return "\001"; 728 } 729 // Check if the first character is \001. We use this to 730 // force sorting of certain special files, like the silent ringtone. 731 if (name.startsWith("\001")) { 732 sortfirst = true; 733 } 734 name = name.trim().toLowerCase(); 735 if (name.startsWith("the ")) { 736 name = name.substring(4); 737 } 738 if (name.startsWith("an ")) { 739 name = name.substring(3); 740 } 741 if (name.startsWith("a ")) { 742 name = name.substring(2); 743 } 744 if (name.endsWith(", the") || name.endsWith(",the") || 745 name.endsWith(", an") || name.endsWith(",an") || 746 name.endsWith(", a") || name.endsWith(",a")) { 747 name = name.substring(0, name.lastIndexOf(',')); 748 } 749 name = name.replaceAll("[\\[\\]\\(\\)\"'.,?!]", "").trim(); 750 if (name.length() > 0) { 751 // Insert a separator between the characters to avoid 752 // matches on a partial character. If we ever change 753 // to start-of-word-only matches, this can be removed. 754 StringBuilder b = new StringBuilder(); 755 b.append('.'); 756 int nl = name.length(); 757 for (int i = 0; i < nl; i++) { 758 b.append(name.charAt(i)); 759 b.append('.'); 760 } 761 name = b.toString(); 762 String key = DatabaseUtils.getCollationKey(name); 763 if (sortfirst) { 764 key = "\001" + key; 765 } 766 return key; 767 } else { 768 return ""; 769 } 770 } 771 return null; 772 } 773 774 public static final class Media implements AudioColumns { 775 /** 776 * Get the content:// style URI for the audio media table on the 777 * given volume. 778 * 779 * @param volumeName the name of the volume to get the URI for 780 * @return the URI to the audio media table on the given volume 781 */ 782 public static Uri getContentUri(String volumeName) { 783 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 784 "/audio/media"); 785 } 786 787 public static Uri getContentUriForPath(String path) { 788 return (path.startsWith(Environment.getExternalStorageDirectory().getPath()) ? 789 EXTERNAL_CONTENT_URI : INTERNAL_CONTENT_URI); 790 } 791 792 /** 793 * The content:// style URI for the internal storage. 794 */ 795 public static final Uri INTERNAL_CONTENT_URI = 796 getContentUri("internal"); 797 798 /** 799 * The content:// style URI for the "primary" external storage 800 * volume. 801 */ 802 public static final Uri EXTERNAL_CONTENT_URI = 803 getContentUri("external"); 804 805 /** 806 * The MIME type for this table. 807 */ 808 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/audio"; 809 810 /** 811 * The default sort order for this table 812 */ 813 public static final String DEFAULT_SORT_ORDER = TITLE_KEY; 814 815 /** 816 * Activity Action: Start SoundRecorder application. 817 * <p>Input: nothing. 818 * <p>Output: An uri to the recorded sound stored in the Media Library 819 * if the recording was successful. 820 * May also contain the extra EXTRA_MAX_BYTES. 821 * @see #EXTRA_MAX_BYTES 822 */ 823 public static final String RECORD_SOUND_ACTION = 824 "android.provider.MediaStore.RECORD_SOUND"; 825 826 /** 827 * The name of the Intent-extra used to define a maximum file size for 828 * a recording made by the SoundRecorder application. 829 * 830 * @see #RECORD_SOUND_ACTION 831 */ 832 public static final String EXTRA_MAX_BYTES = 833 "android.provider.MediaStore.extra.MAX_BYTES"; 834 } 835 836 /** 837 * Columns representing an audio genre 838 */ 839 public interface GenresColumns { 840 /** 841 * The name of the genre 842 * <P>Type: TEXT</P> 843 */ 844 public static final String NAME = "name"; 845 } 846 847 /** 848 * Contains all genres for audio files 849 */ 850 public static final class Genres implements BaseColumns, GenresColumns { 851 /** 852 * Get the content:// style URI for the audio genres table on the 853 * given volume. 854 * 855 * @param volumeName the name of the volume to get the URI for 856 * @return the URI to the audio genres table on the given volume 857 */ 858 public static Uri getContentUri(String volumeName) { 859 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 860 "/audio/genres"); 861 } 862 863 /** 864 * The content:// style URI for the internal storage. 865 */ 866 public static final Uri INTERNAL_CONTENT_URI = 867 getContentUri("internal"); 868 869 /** 870 * The content:// style URI for the "primary" external storage 871 * volume. 872 */ 873 public static final Uri EXTERNAL_CONTENT_URI = 874 getContentUri("external"); 875 876 /** 877 * The MIME type for this table. 878 */ 879 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/genre"; 880 881 /** 882 * The MIME type for entries in this table. 883 */ 884 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/genre"; 885 886 /** 887 * The default sort order for this table 888 */ 889 public static final String DEFAULT_SORT_ORDER = NAME; 890 891 /** 892 * Sub-directory of each genre containing all members. 893 */ 894 public static final class Members implements AudioColumns { 895 896 public static final Uri getContentUri(String volumeName, 897 long genreId) { 898 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName 899 + "/audio/genres/" + genreId + "/members"); 900 } 901 902 /** 903 * A subdirectory of each genre containing all member audio files. 904 */ 905 public static final String CONTENT_DIRECTORY = "members"; 906 907 /** 908 * The default sort order for this table 909 */ 910 public static final String DEFAULT_SORT_ORDER = TITLE_KEY; 911 912 /** 913 * The ID of the audio file 914 * <P>Type: INTEGER (long)</P> 915 */ 916 public static final String AUDIO_ID = "audio_id"; 917 918 /** 919 * The ID of the genre 920 * <P>Type: INTEGER (long)</P> 921 */ 922 public static final String GENRE_ID = "genre_id"; 923 } 924 } 925 926 /** 927 * Columns representing a playlist 928 */ 929 public interface PlaylistsColumns { 930 /** 931 * The name of the playlist 932 * <P>Type: TEXT</P> 933 */ 934 public static final String NAME = "name"; 935 936 /** 937 * The data stream for the playlist file 938 * <P>Type: DATA STREAM</P> 939 */ 940 public static final String DATA = "_data"; 941 942 /** 943 * The time the file was added to the media provider 944 * Units are seconds since 1970. 945 * <P>Type: INTEGER (long)</P> 946 */ 947 public static final String DATE_ADDED = "date_added"; 948 949 /** 950 * The time the file was last modified 951 * Units are seconds since 1970. 952 * NOTE: This is for internal use by the media scanner. Do not modify this field. 953 * <P>Type: INTEGER (long)</P> 954 */ 955 public static final String DATE_MODIFIED = "date_modified"; 956 } 957 958 /** 959 * Contains playlists for audio files 960 */ 961 public static final class Playlists implements BaseColumns, 962 PlaylistsColumns { 963 /** 964 * Get the content:// style URI for the audio playlists table on the 965 * given volume. 966 * 967 * @param volumeName the name of the volume to get the URI for 968 * @return the URI to the audio playlists table on the given volume 969 */ 970 public static Uri getContentUri(String volumeName) { 971 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 972 "/audio/playlists"); 973 } 974 975 /** 976 * The content:// style URI for the internal storage. 977 */ 978 public static final Uri INTERNAL_CONTENT_URI = 979 getContentUri("internal"); 980 981 /** 982 * The content:// style URI for the "primary" external storage 983 * volume. 984 */ 985 public static final Uri EXTERNAL_CONTENT_URI = 986 getContentUri("external"); 987 988 /** 989 * The MIME type for this table. 990 */ 991 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/playlist"; 992 993 /** 994 * The MIME type for entries in this table. 995 */ 996 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/playlist"; 997 998 /** 999 * The default sort order for this table 1000 */ 1001 public static final String DEFAULT_SORT_ORDER = NAME; 1002 1003 /** 1004 * Sub-directory of each playlist containing all members. 1005 */ 1006 public static final class Members implements AudioColumns { 1007 public static final Uri getContentUri(String volumeName, 1008 long playlistId) { 1009 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName 1010 + "/audio/playlists/" + playlistId + "/members"); 1011 } 1012 1013 /** 1014 * The ID within the playlist. 1015 */ 1016 public static final String _ID = "_id"; 1017 1018 /** 1019 * A subdirectory of each playlist containing all member audio 1020 * files. 1021 */ 1022 public static final String CONTENT_DIRECTORY = "members"; 1023 1024 /** 1025 * The ID of the audio file 1026 * <P>Type: INTEGER (long)</P> 1027 */ 1028 public static final String AUDIO_ID = "audio_id"; 1029 1030 /** 1031 * The ID of the playlist 1032 * <P>Type: INTEGER (long)</P> 1033 */ 1034 public static final String PLAYLIST_ID = "playlist_id"; 1035 1036 /** 1037 * The order of the songs in the playlist 1038 * <P>Type: INTEGER (long)></P> 1039 */ 1040 public static final String PLAY_ORDER = "play_order"; 1041 1042 /** 1043 * The default sort order for this table 1044 */ 1045 public static final String DEFAULT_SORT_ORDER = PLAY_ORDER; 1046 } 1047 } 1048 1049 /** 1050 * Columns representing an artist 1051 */ 1052 public interface ArtistColumns { 1053 /** 1054 * The artist who created the audio file, if any 1055 * <P>Type: TEXT</P> 1056 */ 1057 public static final String ARTIST = "artist"; 1058 1059 /** 1060 * A non human readable key calculated from the ARTIST, used for 1061 * searching, sorting and grouping 1062 * <P>Type: TEXT</P> 1063 */ 1064 public static final String ARTIST_KEY = "artist_key"; 1065 1066 /** 1067 * The number of albums in the database for this artist 1068 */ 1069 public static final String NUMBER_OF_ALBUMS = "number_of_albums"; 1070 1071 /** 1072 * The number of albums in the database for this artist 1073 */ 1074 public static final String NUMBER_OF_TRACKS = "number_of_tracks"; 1075 } 1076 1077 /** 1078 * Contains artists for audio files 1079 */ 1080 public static final class Artists implements BaseColumns, ArtistColumns { 1081 /** 1082 * Get the content:// style URI for the artists table on the 1083 * given volume. 1084 * 1085 * @param volumeName the name of the volume to get the URI for 1086 * @return the URI to the audio artists table on the given volume 1087 */ 1088 public static Uri getContentUri(String volumeName) { 1089 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 1090 "/audio/artists"); 1091 } 1092 1093 /** 1094 * The content:// style URI for the internal storage. 1095 */ 1096 public static final Uri INTERNAL_CONTENT_URI = 1097 getContentUri("internal"); 1098 1099 /** 1100 * The content:// style URI for the "primary" external storage 1101 * volume. 1102 */ 1103 public static final Uri EXTERNAL_CONTENT_URI = 1104 getContentUri("external"); 1105 1106 /** 1107 * The MIME type for this table. 1108 */ 1109 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/artists"; 1110 1111 /** 1112 * The MIME type for entries in this table. 1113 */ 1114 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/artist"; 1115 1116 /** 1117 * The default sort order for this table 1118 */ 1119 public static final String DEFAULT_SORT_ORDER = ARTIST_KEY; 1120 1121 /** 1122 * Sub-directory of each artist containing all albums on which 1123 * a song by the artist appears. 1124 */ 1125 public static final class Albums implements AlbumColumns { 1126 public static final Uri getContentUri(String volumeName, 1127 long artistId) { 1128 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName 1129 + "/audio/artists/" + artistId + "/albums"); 1130 } 1131 } 1132 } 1133 1134 /** 1135 * Columns representing an album 1136 */ 1137 public interface AlbumColumns { 1138 1139 /** 1140 * The id for the album 1141 * <P>Type: INTEGER</P> 1142 */ 1143 public static final String ALBUM_ID = "album_id"; 1144 1145 /** 1146 * The album on which the audio file appears, if any 1147 * <P>Type: TEXT</P> 1148 */ 1149 public static final String ALBUM = "album"; 1150 1151 /** 1152 * The artist whose songs appear on this album 1153 * <P>Type: TEXT</P> 1154 */ 1155 public static final String ARTIST = "artist"; 1156 1157 /** 1158 * The number of songs on this album 1159 * <P>Type: INTEGER</P> 1160 */ 1161 public static final String NUMBER_OF_SONGS = "numsongs"; 1162 1163 /** 1164 * This column is available when getting album info via artist, 1165 * and indicates the number of songs on the album by the given 1166 * artist. 1167 * <P>Type: INTEGER</P> 1168 */ 1169 public static final String NUMBER_OF_SONGS_FOR_ARTIST = "numsongs_by_artist"; 1170 1171 /** 1172 * The year in which the earliest songs 1173 * on this album were released. This will often 1174 * be the same as {@link #LAST_YEAR}, but for compilation albums 1175 * they might differ. 1176 * <P>Type: INTEGER</P> 1177 */ 1178 public static final String FIRST_YEAR = "minyear"; 1179 1180 /** 1181 * The year in which the latest songs 1182 * on this album were released. This will often 1183 * be the same as {@link #FIRST_YEAR}, but for compilation albums 1184 * they might differ. 1185 * <P>Type: INTEGER</P> 1186 */ 1187 public static final String LAST_YEAR = "maxyear"; 1188 1189 /** 1190 * A non human readable key calculated from the ALBUM, used for 1191 * searching, sorting and grouping 1192 * <P>Type: TEXT</P> 1193 */ 1194 public static final String ALBUM_KEY = "album_key"; 1195 1196 /** 1197 * Cached album art. 1198 * <P>Type: TEXT</P> 1199 */ 1200 public static final String ALBUM_ART = "album_art"; 1201 } 1202 1203 /** 1204 * Contains artists for audio files 1205 */ 1206 public static final class Albums implements BaseColumns, AlbumColumns { 1207 /** 1208 * Get the content:// style URI for the albums table on the 1209 * given volume. 1210 * 1211 * @param volumeName the name of the volume to get the URI for 1212 * @return the URI to the audio albums table on the given volume 1213 */ 1214 public static Uri getContentUri(String volumeName) { 1215 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 1216 "/audio/albums"); 1217 } 1218 1219 /** 1220 * The content:// style URI for the internal storage. 1221 */ 1222 public static final Uri INTERNAL_CONTENT_URI = 1223 getContentUri("internal"); 1224 1225 /** 1226 * The content:// style URI for the "primary" external storage 1227 * volume. 1228 */ 1229 public static final Uri EXTERNAL_CONTENT_URI = 1230 getContentUri("external"); 1231 1232 /** 1233 * The MIME type for this table. 1234 */ 1235 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/albums"; 1236 1237 /** 1238 * The MIME type for entries in this table. 1239 */ 1240 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/album"; 1241 1242 /** 1243 * The default sort order for this table 1244 */ 1245 public static final String DEFAULT_SORT_ORDER = ALBUM_KEY; 1246 } 1247 } 1248 1249 public static final class Video { 1250 1251 /** 1252 * The default sort order for this table. 1253 */ 1254 public static final String DEFAULT_SORT_ORDER = MediaColumns.DISPLAY_NAME; 1255 1256 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) 1257 { 1258 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER); 1259 } 1260 1261 public interface VideoColumns extends MediaColumns { 1262 1263 /** 1264 * The duration of the video file, in ms 1265 * <P>Type: INTEGER (long)</P> 1266 */ 1267 public static final String DURATION = "duration"; 1268 1269 /** 1270 * The artist who created the video file, if any 1271 * <P>Type: TEXT</P> 1272 */ 1273 public static final String ARTIST = "artist"; 1274 1275 /** 1276 * The album the video file is from, if any 1277 * <P>Type: TEXT</P> 1278 */ 1279 public static final String ALBUM = "album"; 1280 1281 /** 1282 * The resolution of the video file, formatted as "XxY" 1283 * <P>Type: TEXT</P> 1284 */ 1285 public static final String RESOLUTION = "resolution"; 1286 1287 /** 1288 * The description of the video recording 1289 * <P>Type: TEXT</P> 1290 */ 1291 public static final String DESCRIPTION = "description"; 1292 1293 /** 1294 * Whether the video should be published as public or private 1295 * <P>Type: INTEGER</P> 1296 */ 1297 public static final String IS_PRIVATE = "isprivate"; 1298 1299 /** 1300 * The user-added tags associated with a video 1301 * <P>Type: TEXT</P> 1302 */ 1303 public static final String TAGS = "tags"; 1304 1305 /** 1306 * The YouTube category of the video 1307 * <P>Type: TEXT</P> 1308 */ 1309 public static final String CATEGORY = "category"; 1310 1311 /** 1312 * The language of the video 1313 * <P>Type: TEXT</P> 1314 */ 1315 public static final String LANGUAGE = "language"; 1316 1317 /** 1318 * The latitude where the image was captured. 1319 * <P>Type: DOUBLE</P> 1320 */ 1321 public static final String LATITUDE = "latitude"; 1322 1323 /** 1324 * The longitude where the image was captured. 1325 * <P>Type: DOUBLE</P> 1326 */ 1327 public static final String LONGITUDE = "longitude"; 1328 1329 /** 1330 * The date & time that the image was taken in units 1331 * of milliseconds since jan 1, 1970. 1332 * <P>Type: INTEGER</P> 1333 */ 1334 public static final String DATE_TAKEN = "datetaken"; 1335 1336 /** 1337 * The mini thumb id. 1338 * <P>Type: INTEGER</P> 1339 */ 1340 public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; 1341 1342 /** 1343 * The bucket id of the video. This is a read-only property that 1344 * is automatically computed from the DATA column. 1345 * <P>Type: TEXT</P> 1346 */ 1347 public static final String BUCKET_ID = "bucket_id"; 1348 1349 /** 1350 * The bucket display name of the video. This is a read-only property that 1351 * is automatically computed from the DATA column. 1352 * <P>Type: TEXT</P> 1353 */ 1354 public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; 1355 1356 /** 1357 * The bookmark for the video. Time in ms. Represents the location in the video that the 1358 * video should start playing at the next time it is opened. If the value is null or 1359 * out of the range 0..DURATION-1 then the video should start playing from the 1360 * beginning. 1361 * <P>Type: INTEGER</P> 1362 */ 1363 public static final String BOOKMARK = "bookmark"; 1364 } 1365 1366 public static final class Media implements VideoColumns { 1367 /** 1368 * Get the content:// style URI for the video media table on the 1369 * given volume. 1370 * 1371 * @param volumeName the name of the volume to get the URI for 1372 * @return the URI to the video media table on the given volume 1373 */ 1374 public static Uri getContentUri(String volumeName) { 1375 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 1376 "/video/media"); 1377 } 1378 1379 /** 1380 * The content:// style URI for the internal storage. 1381 */ 1382 public static final Uri INTERNAL_CONTENT_URI = 1383 getContentUri("internal"); 1384 1385 /** 1386 * The content:// style URI for the "primary" external storage 1387 * volume. 1388 */ 1389 public static final Uri EXTERNAL_CONTENT_URI = 1390 getContentUri("external"); 1391 1392 /** 1393 * The MIME type for this table. 1394 */ 1395 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/video"; 1396 1397 /** 1398 * The default sort order for this table 1399 */ 1400 public static final String DEFAULT_SORT_ORDER = TITLE; 1401 } 1402 } 1403 1404 /** 1405 * Uri for querying the state of the media scanner. 1406 */ 1407 public static Uri getMediaScannerUri() { 1408 return Uri.parse(CONTENT_AUTHORITY_SLASH + "none/media_scanner"); 1409 } 1410 1411 /** 1412 * Name of current volume being scanned by the media scanner. 1413 */ 1414 public static final String MEDIA_SCANNER_VOLUME = "volume"; 1415} 1416