MediaStore.java revision 15ab3eae2ec3d73b3e8aa60b33ae41445bf83f4b
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 return insertImage(cr, BitmapFactory.decodeFile(imagePath), name, description); 348 } finally { 349 try { 350 stream.close(); 351 } catch (IOException e) { 352 } 353 } 354 } 355 356 private static final Bitmap StoreThumbnail( 357 ContentResolver cr, 358 Bitmap source, 359 long id, 360 float width, float height, 361 int kind) { 362 // create the matrix to scale it 363 Matrix matrix = new Matrix(); 364 365 float scaleX = width / source.getWidth(); 366 float scaleY = height / source.getHeight(); 367 368 matrix.setScale(scaleX, scaleY); 369 370 Bitmap thumb = Bitmap.createBitmap(source, 0, 0, 371 source.getWidth(), 372 source.getHeight(), matrix, 373 true); 374 375 ContentValues values = new ContentValues(4); 376 values.put(Images.Thumbnails.KIND, kind); 377 values.put(Images.Thumbnails.IMAGE_ID, (int)id); 378 values.put(Images.Thumbnails.HEIGHT, thumb.getHeight()); 379 values.put(Images.Thumbnails.WIDTH, thumb.getWidth()); 380 381 Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values); 382 383 try { 384 OutputStream thumbOut = cr.openOutputStream(url); 385 386 thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut); 387 thumbOut.close(); 388 return thumb; 389 } 390 catch (FileNotFoundException ex) { 391 return null; 392 } 393 catch (IOException ex) { 394 return null; 395 } 396 } 397 398 /** 399 * Insert an image and create a thumbnail for it. 400 * 401 * @param cr The content resolver to use 402 * @param source The stream to use for the image 403 * @param title The name of the image 404 * @param description The description of the image 405 * @return The URL to the newly created image, or <code>null</code> if the image failed to be stored 406 * for any reason. 407 */ 408 public static final String insertImage(ContentResolver cr, Bitmap source, 409 String title, String description) 410 { 411 ContentValues values = new ContentValues(); 412 values.put(Images.Media.TITLE, title); 413 values.put(Images.Media.DESCRIPTION, description); 414 values.put(Images.Media.MIME_TYPE, "image/jpeg"); 415 416 Uri url = null; 417 String stringUrl = null; /* value to be returned */ 418 419 try 420 { 421 url = cr.insert(EXTERNAL_CONTENT_URI, values); 422 423 if (source != null) { 424 OutputStream imageOut = cr.openOutputStream(url); 425 try { 426 source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut); 427 } finally { 428 imageOut.close(); 429 } 430 431 long id = ContentUris.parseId(url); 432 Bitmap miniThumb = StoreThumbnail(cr, source, id, 320F, 240F, Images.Thumbnails.MINI_KIND); 433 Bitmap microThumb = StoreThumbnail(cr, miniThumb, id, 50F, 50F, Images.Thumbnails.MICRO_KIND); 434 } else { 435 Log.e(TAG, "Failed to create thumbnail, removing original"); 436 cr.delete(url, null, null); 437 url = null; 438 } 439 } catch (Exception e) { 440 Log.e(TAG, "Failed to insert image", e); 441 if (url != null) { 442 cr.delete(url, null, null); 443 url = null; 444 } 445 } 446 447 if (url != null) { 448 stringUrl = url.toString(); 449 } 450 451 return stringUrl; 452 } 453 454 /** 455 * Get the content:// style URI for the image media table on the 456 * given volume. 457 * 458 * @param volumeName the name of the volume to get the URI for 459 * @return the URI to the image media table on the given volume 460 */ 461 public static Uri getContentUri(String volumeName) { 462 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 463 "/images/media"); 464 } 465 466 /** 467 * The content:// style URI for the internal storage. 468 */ 469 public static final Uri INTERNAL_CONTENT_URI = 470 getContentUri("internal"); 471 472 /** 473 * The content:// style URI for the "primary" external storage 474 * volume. 475 */ 476 public static final Uri EXTERNAL_CONTENT_URI = 477 getContentUri("external"); 478 479 /** 480 * The MIME type of of this directory of 481 * images. Note that each entry in this directory will have a standard 482 * image MIME type as appropriate -- for example, image/jpeg. 483 */ 484 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/image"; 485 486 /** 487 * The default sort order for this table 488 */ 489 public static final String DEFAULT_SORT_ORDER = ImageColumns.BUCKET_DISPLAY_NAME; 490 } 491 492 public static class Thumbnails implements BaseColumns 493 { 494 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) 495 { 496 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER); 497 } 498 499 public static final Cursor queryMiniThumbnails(ContentResolver cr, Uri uri, int kind, String[] projection) 500 { 501 return cr.query(uri, projection, "kind = " + kind, null, DEFAULT_SORT_ORDER); 502 } 503 504 public static final Cursor queryMiniThumbnail(ContentResolver cr, long origId, int kind, String[] projection) 505 { 506 return cr.query(EXTERNAL_CONTENT_URI, projection, 507 IMAGE_ID + " = " + origId + " AND " + KIND + " = " + 508 kind, null, null); 509 } 510 511 /** 512 * Get the content:// style URI for the image media table on the 513 * given volume. 514 * 515 * @param volumeName the name of the volume to get the URI for 516 * @return the URI to the image media table on the given volume 517 */ 518 public static Uri getContentUri(String volumeName) { 519 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 520 "/images/thumbnails"); 521 } 522 523 /** 524 * The content:// style URI for the internal storage. 525 */ 526 public static final Uri INTERNAL_CONTENT_URI = 527 getContentUri("internal"); 528 529 /** 530 * The content:// style URI for the "primary" external storage 531 * volume. 532 */ 533 public static final Uri EXTERNAL_CONTENT_URI = 534 getContentUri("external"); 535 536 /** 537 * The default sort order for this table 538 */ 539 public static final String DEFAULT_SORT_ORDER = "image_id ASC"; 540 541 /** 542 * The data stream for the thumbnail 543 * <P>Type: DATA STREAM</P> 544 */ 545 public static final String DATA = "_data"; 546 547 /** 548 * The original image for the thumbnal 549 * <P>Type: INTEGER (ID from Images table)</P> 550 */ 551 public static final String IMAGE_ID = "image_id"; 552 553 /** 554 * The kind of the thumbnail 555 * <P>Type: INTEGER (One of the values below)</P> 556 */ 557 public static final String KIND = "kind"; 558 559 public static final int MINI_KIND = 1; 560 public static final int FULL_SCREEN_KIND = 2; 561 public static final int MICRO_KIND = 3; 562 563 /** 564 * The width of the thumbnal 565 * <P>Type: INTEGER (long)</P> 566 */ 567 public static final String WIDTH = "width"; 568 569 /** 570 * The height of the thumbnail 571 * <P>Type: INTEGER (long)</P> 572 */ 573 public static final String HEIGHT = "height"; 574 } 575 } 576 577 /** 578 * Container for all audio content. 579 */ 580 public static final class Audio { 581 /** 582 * Columns for audio file that show up in multiple tables. 583 */ 584 public interface AudioColumns extends MediaColumns { 585 586 /** 587 * A non human readable key calculated from the TITLE, used for 588 * searching, sorting and grouping 589 * <P>Type: TEXT</P> 590 */ 591 public static final String TITLE_KEY = "title_key"; 592 593 /** 594 * The duration of the audio file, in ms 595 * <P>Type: INTEGER (long)</P> 596 */ 597 public static final String DURATION = "duration"; 598 599 /** 600 * The position, in ms, playback was at when playback for this file 601 * was last stopped. 602 * <P>Type: INTEGER (long)</P> 603 * @hide 604 */ 605 public static final String BOOKMARK = "bookmark"; 606 607 /** 608 * The id of the artist who created the audio file, if any 609 * <P>Type: INTEGER (long)</P> 610 */ 611 public static final String ARTIST_ID = "artist_id"; 612 613 /** 614 * The artist who created the audio file, if any 615 * <P>Type: TEXT</P> 616 */ 617 public static final String ARTIST = "artist"; 618 619 /** 620 * A non human readable key calculated from the ARTIST, used for 621 * searching, sorting and grouping 622 * <P>Type: TEXT</P> 623 */ 624 public static final String ARTIST_KEY = "artist_key"; 625 626 /** 627 * The composer of the audio file, if any 628 * <P>Type: TEXT</P> 629 */ 630 public static final String COMPOSER = "composer"; 631 632 /** 633 * The id of the album the audio file is from, if any 634 * <P>Type: INTEGER (long)</P> 635 */ 636 public static final String ALBUM_ID = "album_id"; 637 638 /** 639 * The album the audio file is from, if any 640 * <P>Type: TEXT</P> 641 */ 642 public static final String ALBUM = "album"; 643 644 /** 645 * A non human readable key calculated from the ALBUM, used for 646 * searching, sorting and grouping 647 * <P>Type: TEXT</P> 648 */ 649 public static final String ALBUM_KEY = "album_key"; 650 651 /** 652 * A URI to the album art, if any 653 * <P>Type: TEXT</P> 654 */ 655 public static final String ALBUM_ART = "album_art"; 656 657 /** 658 * The track number of this song on the album, if any. 659 * This number encodes both the track number and the 660 * disc number. For multi-disc sets, this number will 661 * be 1xxx for tracks on the first disc, 2xxx for tracks 662 * on the second disc, etc. 663 * <P>Type: INTEGER</P> 664 */ 665 public static final String TRACK = "track"; 666 667 /** 668 * The year the audio file was recorded, if any 669 * <P>Type: INTEGER</P> 670 */ 671 public static final String YEAR = "year"; 672 673 /** 674 * Non-zero if the audio file is music 675 * <P>Type: INTEGER (boolean)</P> 676 */ 677 public static final String IS_MUSIC = "is_music"; 678 679 /** 680 * Non-zero if the audio file is a podcast 681 * <P>Type: INTEGER (boolean)</P> 682 * @hide 683 */ 684 public static final String IS_PODCAST = "is_podcast"; 685 686 /** 687 * Non-zero id the audio file may be a ringtone 688 * <P>Type: INTEGER (boolean)</P> 689 */ 690 public static final String IS_RINGTONE = "is_ringtone"; 691 692 /** 693 * Non-zero id the audio file may be an alarm 694 * <P>Type: INTEGER (boolean)</P> 695 */ 696 public static final String IS_ALARM = "is_alarm"; 697 698 /** 699 * Non-zero id the audio file may be a notification sound 700 * <P>Type: INTEGER (boolean)</P> 701 */ 702 public static final String IS_NOTIFICATION = "is_notification"; 703 } 704 705 /** 706 * Converts a name to a "key" that can be used for grouping, sorting 707 * and searching. 708 * The rules that govern this conversion are: 709 * - remove 'special' characters like ()[]'!?., 710 * - remove leading/trailing spaces 711 * - convert everything to lowercase 712 * - remove leading "the ", "an " and "a " 713 * - remove trailing ", the|an|a" 714 * - remove accents. This step leaves us with CollationKey data, 715 * which is not human readable 716 * 717 * @param name The artist or album name to convert 718 * @return The "key" for the given name. 719 */ 720 public static String keyFor(String name) { 721 if (name != null) { 722 if (name.equals(android.media.MediaFile.UNKNOWN_STRING)) { 723 return "\001"; 724 } 725 name = name.trim().toLowerCase(); 726 if (name.startsWith("the ")) { 727 name = name.substring(4); 728 } 729 if (name.startsWith("an ")) { 730 name = name.substring(3); 731 } 732 if (name.startsWith("a ")) { 733 name = name.substring(2); 734 } 735 if (name.endsWith(", the") || name.endsWith(",the") || 736 name.endsWith(", an") || name.endsWith(",an") || 737 name.endsWith(", a") || name.endsWith(",a")) { 738 name = name.substring(0, name.lastIndexOf(',')); 739 } 740 name = name.replaceAll("[\\[\\]\\(\\)'.,?!]", "").trim(); 741 if (name.length() > 0) { 742 // Insert a separator between the characters to avoid 743 // matches on a partial character. If we ever change 744 // to start-of-word-only matches, this can be removed. 745 StringBuilder b = new StringBuilder(); 746 b.append('.'); 747 int nl = name.length(); 748 for (int i = 0; i < nl; i++) { 749 b.append(name.charAt(i)); 750 b.append('.'); 751 } 752 name = b.toString(); 753 return DatabaseUtils.getCollationKey(name); 754 } else { 755 return ""; 756 } 757 } 758 return null; 759 } 760 761 public static final class Media implements AudioColumns { 762 /** 763 * Get the content:// style URI for the audio media table on the 764 * given volume. 765 * 766 * @param volumeName the name of the volume to get the URI for 767 * @return the URI to the audio media table on the given volume 768 */ 769 public static Uri getContentUri(String volumeName) { 770 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 771 "/audio/media"); 772 } 773 774 public static Uri getContentUriForPath(String path) { 775 return (path.startsWith(Environment.getExternalStorageDirectory().getPath()) ? 776 EXTERNAL_CONTENT_URI : INTERNAL_CONTENT_URI); 777 } 778 779 /** 780 * The content:// style URI for the internal storage. 781 */ 782 public static final Uri INTERNAL_CONTENT_URI = 783 getContentUri("internal"); 784 785 /** 786 * The content:// style URI for the "primary" external storage 787 * volume. 788 */ 789 public static final Uri EXTERNAL_CONTENT_URI = 790 getContentUri("external"); 791 792 /** 793 * The MIME type for this table. 794 */ 795 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/audio"; 796 797 /** 798 * The default sort order for this table 799 */ 800 public static final String DEFAULT_SORT_ORDER = TITLE; 801 802 /** 803 * Activity Action: Start SoundRecorder application. 804 * <p>Input: nothing. 805 * <p>Output: An uri to the recorded sound stored in the Media Library 806 * if the recording was successful. 807 * May also contain the extra EXTRA_MAX_BYTES. 808 * @see #EXTRA_MAX_BYTES 809 */ 810 public static final String RECORD_SOUND_ACTION = 811 "android.provider.MediaStore.RECORD_SOUND"; 812 813 /** 814 * The name of the Intent-extra used to define a maximum file size for 815 * a recording made by the SoundRecorder application. 816 * 817 * @see #RECORD_SOUND_ACTION 818 */ 819 public static final String EXTRA_MAX_BYTES = 820 "android.provider.MediaStore.extra.MAX_BYTES"; 821 } 822 823 /** 824 * Columns representing an audio genre 825 */ 826 public interface GenresColumns { 827 /** 828 * The name of the genre 829 * <P>Type: TEXT</P> 830 */ 831 public static final String NAME = "name"; 832 } 833 834 /** 835 * Contains all genres for audio files 836 */ 837 public static final class Genres implements BaseColumns, GenresColumns { 838 /** 839 * Get the content:// style URI for the audio genres table on the 840 * given volume. 841 * 842 * @param volumeName the name of the volume to get the URI for 843 * @return the URI to the audio genres table on the given volume 844 */ 845 public static Uri getContentUri(String volumeName) { 846 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 847 "/audio/genres"); 848 } 849 850 /** 851 * The content:// style URI for the internal storage. 852 */ 853 public static final Uri INTERNAL_CONTENT_URI = 854 getContentUri("internal"); 855 856 /** 857 * The content:// style URI for the "primary" external storage 858 * volume. 859 */ 860 public static final Uri EXTERNAL_CONTENT_URI = 861 getContentUri("external"); 862 863 /** 864 * The MIME type for this table. 865 */ 866 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/genre"; 867 868 /** 869 * The MIME type for entries in this table. 870 */ 871 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/genre"; 872 873 /** 874 * The default sort order for this table 875 */ 876 public static final String DEFAULT_SORT_ORDER = NAME; 877 878 /** 879 * Sub-directory of each genre containing all members. 880 */ 881 public static final class Members implements AudioColumns { 882 883 public static final Uri getContentUri(String volumeName, 884 long genreId) { 885 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName 886 + "/audio/genres/" + genreId + "/members"); 887 } 888 889 /** 890 * A subdirectory of each genre containing all member audio files. 891 */ 892 public static final String CONTENT_DIRECTORY = "members"; 893 894 /** 895 * The default sort order for this table 896 */ 897 public static final String DEFAULT_SORT_ORDER = TITLE; 898 899 /** 900 * The ID of the audio file 901 * <P>Type: INTEGER (long)</P> 902 */ 903 public static final String AUDIO_ID = "audio_id"; 904 905 /** 906 * The ID of the genre 907 * <P>Type: INTEGER (long)</P> 908 */ 909 public static final String GENRE_ID = "genre_id"; 910 } 911 } 912 913 /** 914 * Columns representing a playlist 915 */ 916 public interface PlaylistsColumns { 917 /** 918 * The name of the playlist 919 * <P>Type: TEXT</P> 920 */ 921 public static final String NAME = "name"; 922 923 /** 924 * The data stream for the playlist file 925 * <P>Type: DATA STREAM</P> 926 */ 927 public static final String DATA = "_data"; 928 929 /** 930 * The time the file was added to the media provider 931 * Units are seconds since 1970. 932 * <P>Type: INTEGER (long)</P> 933 */ 934 public static final String DATE_ADDED = "date_added"; 935 936 /** 937 * The time the file was last modified 938 * Units are seconds since 1970. 939 * NOTE: This is for internal use by the media scanner. Do not modify this field. 940 * <P>Type: INTEGER (long)</P> 941 */ 942 public static final String DATE_MODIFIED = "date_modified"; 943 } 944 945 /** 946 * Contains playlists for audio files 947 */ 948 public static final class Playlists implements BaseColumns, 949 PlaylistsColumns { 950 /** 951 * Get the content:// style URI for the audio playlists table on the 952 * given volume. 953 * 954 * @param volumeName the name of the volume to get the URI for 955 * @return the URI to the audio playlists table on the given volume 956 */ 957 public static Uri getContentUri(String volumeName) { 958 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 959 "/audio/playlists"); 960 } 961 962 /** 963 * The content:// style URI for the internal storage. 964 */ 965 public static final Uri INTERNAL_CONTENT_URI = 966 getContentUri("internal"); 967 968 /** 969 * The content:// style URI for the "primary" external storage 970 * volume. 971 */ 972 public static final Uri EXTERNAL_CONTENT_URI = 973 getContentUri("external"); 974 975 /** 976 * The MIME type for this table. 977 */ 978 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/playlist"; 979 980 /** 981 * The MIME type for entries in this table. 982 */ 983 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/playlist"; 984 985 /** 986 * The default sort order for this table 987 */ 988 public static final String DEFAULT_SORT_ORDER = NAME; 989 990 /** 991 * Sub-directory of each playlist containing all members. 992 */ 993 public static final class Members implements AudioColumns { 994 public static final Uri getContentUri(String volumeName, 995 long playlistId) { 996 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName 997 + "/audio/playlists/" + playlistId + "/members"); 998 } 999 1000 /** 1001 * The ID within the playlist. 1002 */ 1003 public static final String _ID = "_id"; 1004 1005 /** 1006 * A subdirectory of each playlist containing all member audio 1007 * files. 1008 */ 1009 public static final String CONTENT_DIRECTORY = "members"; 1010 1011 /** 1012 * The ID of the audio file 1013 * <P>Type: INTEGER (long)</P> 1014 */ 1015 public static final String AUDIO_ID = "audio_id"; 1016 1017 /** 1018 * The ID of the playlist 1019 * <P>Type: INTEGER (long)</P> 1020 */ 1021 public static final String PLAYLIST_ID = "playlist_id"; 1022 1023 /** 1024 * The order of the songs in the playlist 1025 * <P>Type: INTEGER (long)></P> 1026 */ 1027 public static final String PLAY_ORDER = "play_order"; 1028 1029 /** 1030 * The default sort order for this table 1031 */ 1032 public static final String DEFAULT_SORT_ORDER = PLAY_ORDER; 1033 } 1034 } 1035 1036 /** 1037 * Columns representing an artist 1038 */ 1039 public interface ArtistColumns { 1040 /** 1041 * The artist who created the audio file, if any 1042 * <P>Type: TEXT</P> 1043 */ 1044 public static final String ARTIST = "artist"; 1045 1046 /** 1047 * A non human readable key calculated from the ARTIST, used for 1048 * searching, sorting and grouping 1049 * <P>Type: TEXT</P> 1050 */ 1051 public static final String ARTIST_KEY = "artist_key"; 1052 1053 /** 1054 * The number of albums in the database for this artist 1055 */ 1056 public static final String NUMBER_OF_ALBUMS = "number_of_albums"; 1057 1058 /** 1059 * The number of albums in the database for this artist 1060 */ 1061 public static final String NUMBER_OF_TRACKS = "number_of_tracks"; 1062 } 1063 1064 /** 1065 * Contains artists for audio files 1066 */ 1067 public static final class Artists implements BaseColumns, ArtistColumns { 1068 /** 1069 * Get the content:// style URI for the artists table on the 1070 * given volume. 1071 * 1072 * @param volumeName the name of the volume to get the URI for 1073 * @return the URI to the audio artists table on the given volume 1074 */ 1075 public static Uri getContentUri(String volumeName) { 1076 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 1077 "/audio/artists"); 1078 } 1079 1080 /** 1081 * The content:// style URI for the internal storage. 1082 */ 1083 public static final Uri INTERNAL_CONTENT_URI = 1084 getContentUri("internal"); 1085 1086 /** 1087 * The content:// style URI for the "primary" external storage 1088 * volume. 1089 */ 1090 public static final Uri EXTERNAL_CONTENT_URI = 1091 getContentUri("external"); 1092 1093 /** 1094 * The MIME type for this table. 1095 */ 1096 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/artists"; 1097 1098 /** 1099 * The MIME type for entries in this table. 1100 */ 1101 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/artist"; 1102 1103 /** 1104 * The default sort order for this table 1105 */ 1106 public static final String DEFAULT_SORT_ORDER = ARTIST_KEY; 1107 1108 /** 1109 * Sub-directory of each artist containing all albums on which 1110 * a song by the artist appears. 1111 */ 1112 public static final class Albums implements AlbumColumns { 1113 public static final Uri getContentUri(String volumeName, 1114 long artistId) { 1115 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName 1116 + "/audio/artists/" + artistId + "/albums"); 1117 } 1118 } 1119 } 1120 1121 /** 1122 * Columns representing an album 1123 */ 1124 public interface AlbumColumns { 1125 1126 /** 1127 * The id for the album 1128 * <P>Type: INTEGER</P> 1129 */ 1130 public static final String ALBUM_ID = "album_id"; 1131 1132 /** 1133 * The album on which the audio file appears, if any 1134 * <P>Type: TEXT</P> 1135 */ 1136 public static final String ALBUM = "album"; 1137 1138 /** 1139 * The artist whose songs appear on this album 1140 * <P>Type: TEXT</P> 1141 */ 1142 public static final String ARTIST = "artist"; 1143 1144 /** 1145 * The number of songs on this album 1146 * <P>Type: INTEGER</P> 1147 */ 1148 public static final String NUMBER_OF_SONGS = "numsongs"; 1149 1150 /** 1151 * This column is available when getting album info via artist, 1152 * and indicates the number of songs on the album by the given 1153 * artist. 1154 * <P>Type: INTEGER</P> 1155 * 1156 * @hide pending API Council approval 1157 */ 1158 public static final String NUMBER_OF_SONGS_FOR_ARTIST = "numsongs_by_artist"; 1159 1160 /** 1161 * The year in which the earliest and latest songs 1162 * on this album were released. These will often 1163 * be the same, but for compilation albums they 1164 * might differ. 1165 * <P>Type: INTEGER</P> 1166 */ 1167 public static final String FIRST_YEAR = "minyear"; 1168 public static final String LAST_YEAR = "maxyear"; 1169 1170 /** 1171 * A non human readable key calculated from the ALBUM, used for 1172 * searching, sorting and grouping 1173 * <P>Type: TEXT</P> 1174 */ 1175 public static final String ALBUM_KEY = "album_key"; 1176 1177 /** 1178 * Cached album art. 1179 * <P>Type: TEXT</P> 1180 */ 1181 public static final String ALBUM_ART = "album_art"; 1182 } 1183 1184 /** 1185 * Contains artists for audio files 1186 */ 1187 public static final class Albums implements BaseColumns, AlbumColumns { 1188 /** 1189 * Get the content:// style URI for the albums table on the 1190 * given volume. 1191 * 1192 * @param volumeName the name of the volume to get the URI for 1193 * @return the URI to the audio albums table on the given volume 1194 */ 1195 public static Uri getContentUri(String volumeName) { 1196 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 1197 "/audio/albums"); 1198 } 1199 1200 /** 1201 * The content:// style URI for the internal storage. 1202 */ 1203 public static final Uri INTERNAL_CONTENT_URI = 1204 getContentUri("internal"); 1205 1206 /** 1207 * The content:// style URI for the "primary" external storage 1208 * volume. 1209 */ 1210 public static final Uri EXTERNAL_CONTENT_URI = 1211 getContentUri("external"); 1212 1213 /** 1214 * The MIME type for this table. 1215 */ 1216 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/albums"; 1217 1218 /** 1219 * The MIME type for entries in this table. 1220 */ 1221 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/album"; 1222 1223 /** 1224 * The default sort order for this table 1225 */ 1226 public static final String DEFAULT_SORT_ORDER = ALBUM_KEY; 1227 } 1228 } 1229 1230 public static final class Video { 1231 1232 /** 1233 * The default sort order for this table. 1234 */ 1235 public static final String DEFAULT_SORT_ORDER = MediaColumns.DISPLAY_NAME; 1236 1237 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) 1238 { 1239 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER); 1240 } 1241 1242 public interface VideoColumns extends MediaColumns { 1243 1244 /** 1245 * The duration of the video file, in ms 1246 * <P>Type: INTEGER (long)</P> 1247 */ 1248 public static final String DURATION = "duration"; 1249 1250 /** 1251 * The artist who created the video file, if any 1252 * <P>Type: TEXT</P> 1253 */ 1254 public static final String ARTIST = "artist"; 1255 1256 /** 1257 * The album the video file is from, if any 1258 * <P>Type: TEXT</P> 1259 */ 1260 public static final String ALBUM = "album"; 1261 1262 /** 1263 * The resolution of the video file, formatted as "XxY" 1264 * <P>Type: TEXT</P> 1265 */ 1266 public static final String RESOLUTION = "resolution"; 1267 1268 /** 1269 * The description of the video recording 1270 * <P>Type: TEXT</P> 1271 */ 1272 public static final String DESCRIPTION = "description"; 1273 1274 /** 1275 * Whether the video should be published as public or private 1276 * <P>Type: INTEGER</P> 1277 */ 1278 public static final String IS_PRIVATE = "isprivate"; 1279 1280 /** 1281 * The user-added tags associated with a video 1282 * <P>Type: TEXT</P> 1283 */ 1284 public static final String TAGS = "tags"; 1285 1286 /** 1287 * The YouTube category of the video 1288 * <P>Type: TEXT</P> 1289 */ 1290 public static final String CATEGORY = "category"; 1291 1292 /** 1293 * The language of the video 1294 * <P>Type: TEXT</P> 1295 */ 1296 public static final String LANGUAGE = "language"; 1297 1298 /** 1299 * The latitude where the image was captured. 1300 * <P>Type: DOUBLE</P> 1301 */ 1302 public static final String LATITUDE = "latitude"; 1303 1304 /** 1305 * The longitude where the image was captured. 1306 * <P>Type: DOUBLE</P> 1307 */ 1308 public static final String LONGITUDE = "longitude"; 1309 1310 /** 1311 * The date & time that the image was taken in units 1312 * of milliseconds since jan 1, 1970. 1313 * <P>Type: INTEGER</P> 1314 */ 1315 public static final String DATE_TAKEN = "datetaken"; 1316 1317 /** 1318 * The mini thumb id. 1319 * <P>Type: INTEGER</P> 1320 */ 1321 public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; 1322 1323 /** 1324 * The bucket id of the video. This is a read-only property that 1325 * is automatically computed from the DATA column. 1326 * <P>Type: TEXT</P> 1327 */ 1328 public static final String BUCKET_ID = "bucket_id"; 1329 1330 /** 1331 * The bucket display name of the video. This is a read-only property that 1332 * is automatically computed from the DATA column. 1333 * <P>Type: TEXT</P> 1334 */ 1335 public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; 1336 1337 /** 1338 * The bookmark for the video. Time in ms. Represents the location in the video that the 1339 * video should start playing at the next time it is opened. If the value is null or 1340 * out of the range 0..DURATION-1 then the video should start playing from the 1341 * beginning. 1342 * <P>Type: INTEGER</P> 1343 */ 1344 public static final String BOOKMARK = "bookmark"; 1345 } 1346 1347 public static final class Media implements VideoColumns { 1348 /** 1349 * Get the content:// style URI for the video media table on the 1350 * given volume. 1351 * 1352 * @param volumeName the name of the volume to get the URI for 1353 * @return the URI to the video media table on the given volume 1354 */ 1355 public static Uri getContentUri(String volumeName) { 1356 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName + 1357 "/video/media"); 1358 } 1359 1360 /** 1361 * The content:// style URI for the internal storage. 1362 */ 1363 public static final Uri INTERNAL_CONTENT_URI = 1364 getContentUri("internal"); 1365 1366 /** 1367 * The content:// style URI for the "primary" external storage 1368 * volume. 1369 */ 1370 public static final Uri EXTERNAL_CONTENT_URI = 1371 getContentUri("external"); 1372 1373 /** 1374 * The MIME type for this table. 1375 */ 1376 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/video"; 1377 1378 /** 1379 * The default sort order for this table 1380 */ 1381 public static final String DEFAULT_SORT_ORDER = TITLE; 1382 } 1383 } 1384 1385 /** 1386 * Uri for querying the state of the media scanner. 1387 */ 1388 public static Uri getMediaScannerUri() { 1389 return Uri.parse(CONTENT_AUTHORITY_SLASH + "none/media_scanner"); 1390 } 1391 1392 /** 1393 * Name of current volume being scanned by the media scanner. 1394 */ 1395 public static final String MEDIA_SCANNER_VOLUME = "volume"; 1396} 1397