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