• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.provider;
18 
19 import android.annotation.SdkConstant;
20 import android.annotation.SdkConstant.SdkConstantType;
21 import android.content.ContentResolver;
22 import android.content.ContentValues;
23 import android.content.ContentUris;
24 import android.database.Cursor;
25 import android.database.DatabaseUtils;
26 import android.database.sqlite.SQLiteException;
27 import android.graphics.Bitmap;
28 import android.graphics.BitmapFactory;
29 import android.graphics.Matrix;
30 import android.media.MiniThumbFile;
31 import android.media.ThumbnailUtil;
32 import android.net.Uri;
33 import android.os.Environment;
34 import android.os.ParcelFileDescriptor;
35 import android.util.Log;
36 
37 import java.io.FileInputStream;
38 import java.io.FileNotFoundException;
39 import java.io.IOException;
40 import java.io.InputStream;
41 import java.io.OutputStream;
42 import java.io.UnsupportedEncodingException;
43 import 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  */
49 public 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          */
cancelThumbnailRequest(ContentResolver cr, long origId, Uri baseUri)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          */
getThumbnail(ContentResolver cr, long origId, int kind, BitmapFactory.Options options, Uri baseUri, boolean isVideo)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                         if (c != null) c.close();
349                         c = cr.query(uri, PROJECTION, null, null, null);
350                         if (c == null || !c.moveToFirst()) {
351                             return null;
352                         }
353                         filePath = c.getString(1);
354                     }
355                     if (isVideo) {
356                         bitmap = ThumbnailUtil.createVideoThumbnail(filePath);
357                         if (kind == MICRO_KIND) {
358                             bitmap = ThumbnailUtil.extractMiniThumb(bitmap,
359                                     ThumbnailUtil.MINI_THUMB_TARGET_SIZE,
360                                     ThumbnailUtil.MINI_THUMB_TARGET_SIZE,
361                                     ThumbnailUtil.RECYCLE_INPUT);
362                         }
363                     } else {
364                         bitmap = ThumbnailUtil.createImageThumbnail(cr, filePath, uri, origId,
365                                 kind, false);
366                     }
367                 }
368             } catch (SQLiteException ex) {
369                 Log.w(TAG, ex);
370             } finally {
371                 if (c != null) c.close();
372             }
373             return bitmap;
374         }
375     }
376 
377     /**
378      * Contains meta data for all available images.
379      */
380     public static final class Images {
381         public interface ImageColumns extends MediaColumns {
382             /**
383              * The description of the image
384              * <P>Type: TEXT</P>
385              */
386             public static final String DESCRIPTION = "description";
387 
388             /**
389              * The picasa id of the image
390              * <P>Type: TEXT</P>
391              */
392             public static final String PICASA_ID = "picasa_id";
393 
394             /**
395              * Whether the video should be published as public or private
396              * <P>Type: INTEGER</P>
397              */
398             public static final String IS_PRIVATE = "isprivate";
399 
400             /**
401              * The latitude where the image was captured.
402              * <P>Type: DOUBLE</P>
403              */
404             public static final String LATITUDE = "latitude";
405 
406             /**
407              * The longitude where the image was captured.
408              * <P>Type: DOUBLE</P>
409              */
410             public static final String LONGITUDE = "longitude";
411 
412             /**
413              * The date & time that the image was taken in units
414              * of milliseconds since jan 1, 1970.
415              * <P>Type: INTEGER</P>
416              */
417             public static final String DATE_TAKEN = "datetaken";
418 
419             /**
420              * The orientation for the image expressed as degrees.
421              * Only degrees 0, 90, 180, 270 will work.
422              * <P>Type: INTEGER</P>
423              */
424             public static final String ORIENTATION = "orientation";
425 
426             /**
427              * The mini thumb id.
428              * <P>Type: INTEGER</P>
429              */
430             public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
431 
432             /**
433              * The bucket id of the image. This is a read-only property that
434              * is automatically computed from the DATA column.
435              * <P>Type: TEXT</P>
436              */
437             public static final String BUCKET_ID = "bucket_id";
438 
439             /**
440              * The bucket display name of the image. This is a read-only property that
441              * is automatically computed from the DATA column.
442              * <P>Type: TEXT</P>
443              */
444             public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
445         }
446 
447         public static final class Media implements ImageColumns {
query(ContentResolver cr, Uri uri, String[] projection)448             public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
449                 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
450             }
451 
query(ContentResolver cr, Uri uri, String[] projection, String where, String orderBy)452             public static final Cursor query(ContentResolver cr, Uri uri, String[] projection,
453                     String where, String orderBy) {
454                 return cr.query(uri, projection, where,
455                                              null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
456             }
457 
query(ContentResolver cr, Uri uri, String[] projection, String selection, String [] selectionArgs, String orderBy)458             public static final Cursor query(ContentResolver cr, Uri uri, String[] projection,
459                     String selection, String [] selectionArgs, String orderBy) {
460                 return cr.query(uri, projection, selection,
461                         selectionArgs, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
462             }
463 
464             /**
465              * Retrieves an image for the given url as a {@link Bitmap}.
466              *
467              * @param cr The content resolver to use
468              * @param url The url of the image
469              * @throws FileNotFoundException
470              * @throws IOException
471              */
getBitmap(ContentResolver cr, Uri url)472             public static final Bitmap getBitmap(ContentResolver cr, Uri url)
473                     throws FileNotFoundException, IOException {
474                 InputStream input = cr.openInputStream(url);
475                 Bitmap bitmap = BitmapFactory.decodeStream(input);
476                 input.close();
477                 return bitmap;
478             }
479 
480             /**
481              * Insert an image and create a thumbnail for it.
482              *
483              * @param cr The content resolver to use
484              * @param imagePath The path to the image to insert
485              * @param name The name of the image
486              * @param description The description of the image
487              * @return The URL to the newly created image
488              * @throws FileNotFoundException
489              */
insertImage(ContentResolver cr, String imagePath, String name, String description)490             public static final String insertImage(ContentResolver cr, String imagePath,
491                     String name, String description) throws FileNotFoundException {
492                 // Check if file exists with a FileInputStream
493                 FileInputStream stream = new FileInputStream(imagePath);
494                 try {
495                     Bitmap bm = BitmapFactory.decodeFile(imagePath);
496                     String ret = insertImage(cr, bm, name, description);
497                     bm.recycle();
498                     return ret;
499                 } finally {
500                     try {
501                         stream.close();
502                     } catch (IOException e) {
503                     }
504                 }
505             }
506 
StoreThumbnail( ContentResolver cr, Bitmap source, long id, float width, float height, int kind)507             private static final Bitmap StoreThumbnail(
508                     ContentResolver cr,
509                     Bitmap source,
510                     long id,
511                     float width, float height,
512                     int kind) {
513                 // create the matrix to scale it
514                 Matrix matrix = new Matrix();
515 
516                 float scaleX = width / source.getWidth();
517                 float scaleY = height / source.getHeight();
518 
519                 matrix.setScale(scaleX, scaleY);
520 
521                 Bitmap thumb = Bitmap.createBitmap(source, 0, 0,
522                                                    source.getWidth(),
523                                                    source.getHeight(), matrix,
524                                                    true);
525 
526                 ContentValues values = new ContentValues(4);
527                 values.put(Images.Thumbnails.KIND,     kind);
528                 values.put(Images.Thumbnails.IMAGE_ID, (int)id);
529                 values.put(Images.Thumbnails.HEIGHT,   thumb.getHeight());
530                 values.put(Images.Thumbnails.WIDTH,    thumb.getWidth());
531 
532                 Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values);
533 
534                 try {
535                     OutputStream thumbOut = cr.openOutputStream(url);
536 
537                     thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut);
538                     thumbOut.close();
539                     return thumb;
540                 }
541                 catch (FileNotFoundException ex) {
542                     return null;
543                 }
544                 catch (IOException ex) {
545                     return null;
546                 }
547             }
548 
549             /**
550              * Insert an image and create a thumbnail for it.
551              *
552              * @param cr The content resolver to use
553              * @param source The stream to use for the image
554              * @param title The name of the image
555              * @param description The description of the image
556              * @return The URL to the newly created image, or <code>null</code> if the image failed to be stored
557              *              for any reason.
558              */
insertImage(ContentResolver cr, Bitmap source, String title, String description)559             public static final String insertImage(ContentResolver cr, Bitmap source,
560                                                    String title, String description) {
561                 ContentValues values = new ContentValues();
562                 values.put(Images.Media.TITLE, title);
563                 values.put(Images.Media.DESCRIPTION, description);
564                 values.put(Images.Media.MIME_TYPE, "image/jpeg");
565 
566                 Uri url = null;
567                 String stringUrl = null;    /* value to be returned */
568 
569                 try {
570                     url = cr.insert(EXTERNAL_CONTENT_URI, values);
571 
572                     if (source != null) {
573                         OutputStream imageOut = cr.openOutputStream(url);
574                         try {
575                             source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut);
576                         } finally {
577                             imageOut.close();
578                         }
579 
580                         long id = ContentUris.parseId(url);
581                         Bitmap miniThumb  = StoreThumbnail(cr, source, id, 320F, 240F, Images.Thumbnails.MINI_KIND);
582                         Bitmap microThumb = StoreThumbnail(cr, miniThumb, id, 50F, 50F, Images.Thumbnails.MICRO_KIND);
583                     } else {
584                         Log.e(TAG, "Failed to create thumbnail, removing original");
585                         cr.delete(url, null, null);
586                         url = null;
587                     }
588                 } catch (Exception e) {
589                     Log.e(TAG, "Failed to insert image", e);
590                     if (url != null) {
591                         cr.delete(url, null, null);
592                         url = null;
593                     }
594                 }
595 
596                 if (url != null) {
597                     stringUrl = url.toString();
598                 }
599 
600                 return stringUrl;
601             }
602 
603             /**
604              * Get the content:// style URI for the image media table on the
605              * given volume.
606              *
607              * @param volumeName the name of the volume to get the URI for
608              * @return the URI to the image media table on the given volume
609              */
getContentUri(String volumeName)610             public static Uri getContentUri(String volumeName) {
611                 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
612                         "/images/media");
613             }
614 
615             /**
616              * The content:// style URI for the internal storage.
617              */
618             public static final Uri INTERNAL_CONTENT_URI =
619                     getContentUri("internal");
620 
621             /**
622              * The content:// style URI for the "primary" external storage
623              * volume.
624              */
625             public static final Uri EXTERNAL_CONTENT_URI =
626                     getContentUri("external");
627 
628             /**
629              * The MIME type of of this directory of
630              * images.  Note that each entry in this directory will have a standard
631              * image MIME type as appropriate -- for example, image/jpeg.
632              */
633             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/image";
634 
635             /**
636              * The default sort order for this table
637              */
638             public static final String DEFAULT_SORT_ORDER = ImageColumns.BUCKET_DISPLAY_NAME;
639         }
640 
641         /**
642          * This class allows developers to query and get two kinds of thumbnails:
643          * MINI_KIND: 512 x 384 thumbnail
644          * MICRO_KIND: 96 x 96 thumbnail
645          */
646         public static class Thumbnails implements BaseColumns {
query(ContentResolver cr, Uri uri, String[] projection)647             public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
648                 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
649             }
650 
queryMiniThumbnails(ContentResolver cr, Uri uri, int kind, String[] projection)651             public static final Cursor queryMiniThumbnails(ContentResolver cr, Uri uri, int kind,
652                     String[] projection) {
653                 return cr.query(uri, projection, "kind = " + kind, null, DEFAULT_SORT_ORDER);
654             }
655 
queryMiniThumbnail(ContentResolver cr, long origId, int kind, String[] projection)656             public static final Cursor queryMiniThumbnail(ContentResolver cr, long origId, int kind,
657                     String[] projection) {
658                 return cr.query(EXTERNAL_CONTENT_URI, projection,
659                         IMAGE_ID + " = " + origId + " AND " + KIND + " = " +
660                         kind, null, null);
661             }
662 
663             /**
664              * This method cancels the thumbnail request so clients waiting for getThumbnail will be
665              * interrupted and return immediately. Only the original process which made the getThumbnail
666              * requests can cancel their own requests.
667              *
668              * @param cr ContentResolver
669              * @param origId original image id
670              */
cancelThumbnailRequest(ContentResolver cr, long origId)671             public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
672                 InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI);
673             }
674 
675             /**
676              * This method checks if the thumbnails of the specified image (origId) has been created.
677              * It will be blocked until the thumbnails are generated.
678              *
679              * @param cr ContentResolver used to dispatch queries to MediaProvider.
680              * @param origId Original image id associated with thumbnail of interest.
681              * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND.
682              * @param options this is only used for MINI_KIND when decoding the Bitmap
683              * @return A Bitmap instance. It could be null if the original image
684              *         associated with origId doesn't exist or memory is not enough.
685              */
getThumbnail(ContentResolver cr, long origId, int kind, BitmapFactory.Options options)686             public static Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
687                     BitmapFactory.Options options) {
688                 return InternalThumbnails.getThumbnail(cr, origId, kind, options,
689                         EXTERNAL_CONTENT_URI, false);
690             }
691 
692             /**
693              * Get the content:// style URI for the image media table on the
694              * given volume.
695              *
696              * @param volumeName the name of the volume to get the URI for
697              * @return the URI to the image media table on the given volume
698              */
getContentUri(String volumeName)699             public static Uri getContentUri(String volumeName) {
700                 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
701                         "/images/thumbnails");
702             }
703 
704             /**
705              * The content:// style URI for the internal storage.
706              */
707             public static final Uri INTERNAL_CONTENT_URI =
708                     getContentUri("internal");
709 
710             /**
711              * The content:// style URI for the "primary" external storage
712              * volume.
713              */
714             public static final Uri EXTERNAL_CONTENT_URI =
715                     getContentUri("external");
716 
717             /**
718              * The default sort order for this table
719              */
720             public static final String DEFAULT_SORT_ORDER = "image_id ASC";
721 
722             /**
723              * The data stream for the thumbnail
724              * <P>Type: DATA STREAM</P>
725              */
726             public static final String DATA = "_data";
727 
728             /**
729              * The original image for the thumbnal
730              * <P>Type: INTEGER (ID from Images table)</P>
731              */
732             public static final String IMAGE_ID = "image_id";
733 
734             /**
735              * The kind of the thumbnail
736              * <P>Type: INTEGER (One of the values below)</P>
737              */
738             public static final String KIND = "kind";
739 
740             public static final int MINI_KIND = 1;
741             public static final int FULL_SCREEN_KIND = 2;
742             public static final int MICRO_KIND = 3;
743             /**
744              * The blob raw data of thumbnail
745              * <P>Type: DATA STREAM</P>
746              */
747             public static final String THUMB_DATA = "thumb_data";
748 
749             /**
750              * The width of the thumbnal
751              * <P>Type: INTEGER (long)</P>
752              */
753             public static final String WIDTH = "width";
754 
755             /**
756              * The height of the thumbnail
757              * <P>Type: INTEGER (long)</P>
758              */
759             public static final String HEIGHT = "height";
760         }
761     }
762 
763     /**
764      * Container for all audio content.
765      */
766     public static final class Audio {
767         /**
768          * Columns for audio file that show up in multiple tables.
769          */
770         public interface AudioColumns extends MediaColumns {
771 
772             /**
773              * A non human readable key calculated from the TITLE, used for
774              * searching, sorting and grouping
775              * <P>Type: TEXT</P>
776              */
777             public static final String TITLE_KEY = "title_key";
778 
779             /**
780              * The duration of the audio file, in ms
781              * <P>Type: INTEGER (long)</P>
782              */
783             public static final String DURATION = "duration";
784 
785             /**
786              * The position, in ms, playback was at when playback for this file
787              * was last stopped.
788              * <P>Type: INTEGER (long)</P>
789              * @hide
790              */
791             public static final String BOOKMARK = "bookmark";
792 
793             /**
794              * The id of the artist who created the audio file, if any
795              * <P>Type: INTEGER (long)</P>
796              */
797             public static final String ARTIST_ID = "artist_id";
798 
799             /**
800              * The artist who created the audio file, if any
801              * <P>Type: TEXT</P>
802              */
803             public static final String ARTIST = "artist";
804 
805             /**
806              * A non human readable key calculated from the ARTIST, used for
807              * searching, sorting and grouping
808              * <P>Type: TEXT</P>
809              */
810             public static final String ARTIST_KEY = "artist_key";
811 
812             /**
813              * The composer of the audio file, if any
814              * <P>Type: TEXT</P>
815              */
816             public static final String COMPOSER = "composer";
817 
818             /**
819              * The id of the album the audio file is from, if any
820              * <P>Type: INTEGER (long)</P>
821              */
822             public static final String ALBUM_ID = "album_id";
823 
824             /**
825              * The album the audio file is from, if any
826              * <P>Type: TEXT</P>
827              */
828             public static final String ALBUM = "album";
829 
830             /**
831              * A non human readable key calculated from the ALBUM, used for
832              * searching, sorting and grouping
833              * <P>Type: TEXT</P>
834              */
835             public static final String ALBUM_KEY = "album_key";
836 
837             /**
838              * A URI to the album art, if any
839              * <P>Type: TEXT</P>
840              */
841             public static final String ALBUM_ART = "album_art";
842 
843             /**
844              * The track number of this song on the album, if any.
845              * This number encodes both the track number and the
846              * disc number. For multi-disc sets, this number will
847              * be 1xxx for tracks on the first disc, 2xxx for tracks
848              * on the second disc, etc.
849              * <P>Type: INTEGER</P>
850              */
851             public static final String TRACK = "track";
852 
853             /**
854              * The year the audio file was recorded, if any
855              * <P>Type: INTEGER</P>
856              */
857             public static final String YEAR = "year";
858 
859             /**
860              * Non-zero if the audio file is music
861              * <P>Type: INTEGER (boolean)</P>
862              */
863             public static final String IS_MUSIC = "is_music";
864 
865             /**
866              * Non-zero if the audio file is a podcast
867              * <P>Type: INTEGER (boolean)</P>
868              * @hide
869              */
870             public static final String IS_PODCAST = "is_podcast";
871 
872             /**
873              * Non-zero id the audio file may be a ringtone
874              * <P>Type: INTEGER (boolean)</P>
875              */
876             public static final String IS_RINGTONE = "is_ringtone";
877 
878             /**
879              * Non-zero id the audio file may be an alarm
880              * <P>Type: INTEGER (boolean)</P>
881              */
882             public static final String IS_ALARM = "is_alarm";
883 
884             /**
885              * Non-zero id the audio file may be a notification sound
886              * <P>Type: INTEGER (boolean)</P>
887              */
888             public static final String IS_NOTIFICATION = "is_notification";
889         }
890 
891         /**
892          * Converts a name to a "key" that can be used for grouping, sorting
893          * and searching.
894          * The rules that govern this conversion are:
895          * - remove 'special' characters like ()[]'!?.,
896          * - remove leading/trailing spaces
897          * - convert everything to lowercase
898          * - remove leading "the ", "an " and "a "
899          * - remove trailing ", the|an|a"
900          * - remove accents. This step leaves us with CollationKey data,
901          *   which is not human readable
902          *
903          * @param name The artist or album name to convert
904          * @return The "key" for the given name.
905          */
keyFor(String name)906         public static String keyFor(String name) {
907             if (name != null)  {
908                 boolean sortfirst = false;
909                 if (name.equals(android.media.MediaFile.UNKNOWN_STRING)) {
910                     return "\001";
911                 }
912                 // Check if the first character is \001. We use this to
913                 // force sorting of certain special files, like the silent ringtone.
914                 if (name.startsWith("\001")) {
915                     sortfirst = true;
916                 }
917                 name = name.trim().toLowerCase();
918                 if (name.startsWith("the ")) {
919                     name = name.substring(4);
920                 }
921                 if (name.startsWith("an ")) {
922                     name = name.substring(3);
923                 }
924                 if (name.startsWith("a ")) {
925                     name = name.substring(2);
926                 }
927                 if (name.endsWith(", the") || name.endsWith(",the") ||
928                     name.endsWith(", an") || name.endsWith(",an") ||
929                     name.endsWith(", a") || name.endsWith(",a")) {
930                     name = name.substring(0, name.lastIndexOf(','));
931                 }
932                 name = name.replaceAll("[\\[\\]\\(\\)\"'.,?!]", "").trim();
933                 if (name.length() > 0) {
934                     // Insert a separator between the characters to avoid
935                     // matches on a partial character. If we ever change
936                     // to start-of-word-only matches, this can be removed.
937                     StringBuilder b = new StringBuilder();
938                     b.append('.');
939                     int nl = name.length();
940                     for (int i = 0; i < nl; i++) {
941                         b.append(name.charAt(i));
942                         b.append('.');
943                     }
944                     name = b.toString();
945                     String key = DatabaseUtils.getCollationKey(name);
946                     if (sortfirst) {
947                         key = "\001" + key;
948                     }
949                     return key;
950                } else {
951                     return "";
952                 }
953             }
954             return null;
955         }
956 
957         public static final class Media implements AudioColumns {
958             /**
959              * Get the content:// style URI for the audio media table on the
960              * given volume.
961              *
962              * @param volumeName the name of the volume to get the URI for
963              * @return the URI to the audio media table on the given volume
964              */
getContentUri(String volumeName)965             public static Uri getContentUri(String volumeName) {
966                 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
967                         "/audio/media");
968             }
969 
getContentUriForPath(String path)970             public static Uri getContentUriForPath(String path) {
971                 return (path.startsWith(Environment.getExternalStorageDirectory().getPath()) ?
972                         EXTERNAL_CONTENT_URI : INTERNAL_CONTENT_URI);
973             }
974 
975             /**
976              * The content:// style URI for the internal storage.
977              */
978             public static final Uri INTERNAL_CONTENT_URI =
979                     getContentUri("internal");
980 
981             /**
982              * The content:// style URI for the "primary" external storage
983              * volume.
984              */
985             public static final Uri EXTERNAL_CONTENT_URI =
986                     getContentUri("external");
987 
988             /**
989              * The MIME type for this table.
990              */
991             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
992 
993             /**
994              * The default sort order for this table
995              */
996             public static final String DEFAULT_SORT_ORDER = TITLE_KEY;
997 
998             /**
999              * Activity Action: Start SoundRecorder application.
1000              * <p>Input: nothing.
1001              * <p>Output: An uri to the recorded sound stored in the Media Library
1002              * if the recording was successful.
1003              * May also contain the extra EXTRA_MAX_BYTES.
1004              * @see #EXTRA_MAX_BYTES
1005              */
1006             public static final String RECORD_SOUND_ACTION =
1007                     "android.provider.MediaStore.RECORD_SOUND";
1008 
1009             /**
1010              * The name of the Intent-extra used to define a maximum file size for
1011              * a recording made by the SoundRecorder application.
1012              *
1013              * @see #RECORD_SOUND_ACTION
1014              */
1015              public static final String EXTRA_MAX_BYTES =
1016                     "android.provider.MediaStore.extra.MAX_BYTES";
1017         }
1018 
1019         /**
1020          * Columns representing an audio genre
1021          */
1022         public interface GenresColumns {
1023             /**
1024              * The name of the genre
1025              * <P>Type: TEXT</P>
1026              */
1027             public static final String NAME = "name";
1028         }
1029 
1030         /**
1031          * Contains all genres for audio files
1032          */
1033         public static final class Genres implements BaseColumns, GenresColumns {
1034             /**
1035              * Get the content:// style URI for the audio genres table on the
1036              * given volume.
1037              *
1038              * @param volumeName the name of the volume to get the URI for
1039              * @return the URI to the audio genres table on the given volume
1040              */
getContentUri(String volumeName)1041             public static Uri getContentUri(String volumeName) {
1042                 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1043                         "/audio/genres");
1044             }
1045 
1046             /**
1047              * The content:// style URI for the internal storage.
1048              */
1049             public static final Uri INTERNAL_CONTENT_URI =
1050                     getContentUri("internal");
1051 
1052             /**
1053              * The content:// style URI for the "primary" external storage
1054              * volume.
1055              */
1056             public static final Uri EXTERNAL_CONTENT_URI =
1057                     getContentUri("external");
1058 
1059             /**
1060              * The MIME type for this table.
1061              */
1062             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/genre";
1063 
1064             /**
1065              * The MIME type for entries in this table.
1066              */
1067             public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/genre";
1068 
1069             /**
1070              * The default sort order for this table
1071              */
1072             public static final String DEFAULT_SORT_ORDER = NAME;
1073 
1074             /**
1075              * Sub-directory of each genre containing all members.
1076              */
1077             public static final class Members implements AudioColumns {
1078 
getContentUri(String volumeName, long genreId)1079                 public static final Uri getContentUri(String volumeName,
1080                         long genreId) {
1081                     return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
1082                             + "/audio/genres/" + genreId + "/members");
1083                 }
1084 
1085                 /**
1086                  * A subdirectory of each genre containing all member audio files.
1087                  */
1088                 public static final String CONTENT_DIRECTORY = "members";
1089 
1090                 /**
1091                  * The default sort order for this table
1092                  */
1093                 public static final String DEFAULT_SORT_ORDER = TITLE_KEY;
1094 
1095                 /**
1096                  * The ID of the audio file
1097                  * <P>Type: INTEGER (long)</P>
1098                  */
1099                 public static final String AUDIO_ID = "audio_id";
1100 
1101                 /**
1102                  * The ID of the genre
1103                  * <P>Type: INTEGER (long)</P>
1104                  */
1105                 public static final String GENRE_ID = "genre_id";
1106             }
1107         }
1108 
1109         /**
1110          * Columns representing a playlist
1111          */
1112         public interface PlaylistsColumns {
1113             /**
1114              * The name of the playlist
1115              * <P>Type: TEXT</P>
1116              */
1117             public static final String NAME = "name";
1118 
1119             /**
1120              * The data stream for the playlist file
1121              * <P>Type: DATA STREAM</P>
1122              */
1123             public static final String DATA = "_data";
1124 
1125             /**
1126              * The time the file was added to the media provider
1127              * Units are seconds since 1970.
1128              * <P>Type: INTEGER (long)</P>
1129              */
1130             public static final String DATE_ADDED = "date_added";
1131 
1132             /**
1133              * The time the file was last modified
1134              * Units are seconds since 1970.
1135              * NOTE: This is for internal use by the media scanner.  Do not modify this field.
1136              * <P>Type: INTEGER (long)</P>
1137              */
1138             public static final String DATE_MODIFIED = "date_modified";
1139         }
1140 
1141         /**
1142          * Contains playlists for audio files
1143          */
1144         public static final class Playlists implements BaseColumns,
1145                 PlaylistsColumns {
1146             /**
1147              * Get the content:// style URI for the audio playlists table on the
1148              * given volume.
1149              *
1150              * @param volumeName the name of the volume to get the URI for
1151              * @return the URI to the audio playlists table on the given volume
1152              */
getContentUri(String volumeName)1153             public static Uri getContentUri(String volumeName) {
1154                 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1155                         "/audio/playlists");
1156             }
1157 
1158             /**
1159              * The content:// style URI for the internal storage.
1160              */
1161             public static final Uri INTERNAL_CONTENT_URI =
1162                     getContentUri("internal");
1163 
1164             /**
1165              * The content:// style URI for the "primary" external storage
1166              * volume.
1167              */
1168             public static final Uri EXTERNAL_CONTENT_URI =
1169                     getContentUri("external");
1170 
1171             /**
1172              * The MIME type for this table.
1173              */
1174             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/playlist";
1175 
1176             /**
1177              * The MIME type for entries in this table.
1178              */
1179             public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/playlist";
1180 
1181             /**
1182              * The default sort order for this table
1183              */
1184             public static final String DEFAULT_SORT_ORDER = NAME;
1185 
1186             /**
1187              * Sub-directory of each playlist containing all members.
1188              */
1189             public static final class Members implements AudioColumns {
getContentUri(String volumeName, long playlistId)1190                 public static final Uri getContentUri(String volumeName,
1191                         long playlistId) {
1192                     return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
1193                             + "/audio/playlists/" + playlistId + "/members");
1194                 }
1195 
1196                 /**
1197                  * The ID within the playlist.
1198                  */
1199                 public static final String _ID = "_id";
1200 
1201                 /**
1202                  * A subdirectory of each playlist containing all member audio
1203                  * files.
1204                  */
1205                 public static final String CONTENT_DIRECTORY = "members";
1206 
1207                 /**
1208                  * The ID of the audio file
1209                  * <P>Type: INTEGER (long)</P>
1210                  */
1211                 public static final String AUDIO_ID = "audio_id";
1212 
1213                 /**
1214                  * The ID of the playlist
1215                  * <P>Type: INTEGER (long)</P>
1216                  */
1217                 public static final String PLAYLIST_ID = "playlist_id";
1218 
1219                 /**
1220                  * The order of the songs in the playlist
1221                  * <P>Type: INTEGER (long)></P>
1222                  */
1223                 public static final String PLAY_ORDER = "play_order";
1224 
1225                 /**
1226                  * The default sort order for this table
1227                  */
1228                 public static final String DEFAULT_SORT_ORDER = PLAY_ORDER;
1229             }
1230         }
1231 
1232         /**
1233          * Columns representing an artist
1234          */
1235         public interface ArtistColumns {
1236             /**
1237              * The artist who created the audio file, if any
1238              * <P>Type: TEXT</P>
1239              */
1240             public static final String ARTIST = "artist";
1241 
1242             /**
1243              * A non human readable key calculated from the ARTIST, used for
1244              * searching, sorting and grouping
1245              * <P>Type: TEXT</P>
1246              */
1247             public static final String ARTIST_KEY = "artist_key";
1248 
1249             /**
1250              * The number of albums in the database for this artist
1251              */
1252             public static final String NUMBER_OF_ALBUMS = "number_of_albums";
1253 
1254             /**
1255              * The number of albums in the database for this artist
1256              */
1257             public static final String NUMBER_OF_TRACKS = "number_of_tracks";
1258         }
1259 
1260         /**
1261          * Contains artists for audio files
1262          */
1263         public static final class Artists implements BaseColumns, ArtistColumns {
1264             /**
1265              * Get the content:// style URI for the artists table on the
1266              * given volume.
1267              *
1268              * @param volumeName the name of the volume to get the URI for
1269              * @return the URI to the audio artists table on the given volume
1270              */
getContentUri(String volumeName)1271             public static Uri getContentUri(String volumeName) {
1272                 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1273                         "/audio/artists");
1274             }
1275 
1276             /**
1277              * The content:// style URI for the internal storage.
1278              */
1279             public static final Uri INTERNAL_CONTENT_URI =
1280                     getContentUri("internal");
1281 
1282             /**
1283              * The content:// style URI for the "primary" external storage
1284              * volume.
1285              */
1286             public static final Uri EXTERNAL_CONTENT_URI =
1287                     getContentUri("external");
1288 
1289             /**
1290              * The MIME type for this table.
1291              */
1292             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/artists";
1293 
1294             /**
1295              * The MIME type for entries in this table.
1296              */
1297             public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/artist";
1298 
1299             /**
1300              * The default sort order for this table
1301              */
1302             public static final String DEFAULT_SORT_ORDER = ARTIST_KEY;
1303 
1304             /**
1305              * Sub-directory of each artist containing all albums on which
1306              * a song by the artist appears.
1307              */
1308             public static final class Albums implements AlbumColumns {
getContentUri(String volumeName, long artistId)1309                 public static final Uri getContentUri(String volumeName,
1310                         long artistId) {
1311                     return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
1312                             + "/audio/artists/" + artistId + "/albums");
1313                 }
1314             }
1315         }
1316 
1317         /**
1318          * Columns representing an album
1319          */
1320         public interface AlbumColumns {
1321 
1322             /**
1323              * The id for the album
1324              * <P>Type: INTEGER</P>
1325              */
1326             public static final String ALBUM_ID = "album_id";
1327 
1328             /**
1329              * The album on which the audio file appears, if any
1330              * <P>Type: TEXT</P>
1331              */
1332             public static final String ALBUM = "album";
1333 
1334             /**
1335              * The artist whose songs appear on this album
1336              * <P>Type: TEXT</P>
1337              */
1338             public static final String ARTIST = "artist";
1339 
1340             /**
1341              * The number of songs on this album
1342              * <P>Type: INTEGER</P>
1343              */
1344             public static final String NUMBER_OF_SONGS = "numsongs";
1345 
1346             /**
1347              * This column is available when getting album info via artist,
1348              * and indicates the number of songs on the album by the given
1349              * artist.
1350              * <P>Type: INTEGER</P>
1351              */
1352             public static final String NUMBER_OF_SONGS_FOR_ARTIST = "numsongs_by_artist";
1353 
1354             /**
1355              * The year in which the earliest songs
1356              * on this album were released. This will often
1357              * be the same as {@link #LAST_YEAR}, but for compilation albums
1358              * they might differ.
1359              * <P>Type: INTEGER</P>
1360              */
1361             public static final String FIRST_YEAR = "minyear";
1362 
1363             /**
1364              * The year in which the latest songs
1365              * on this album were released. This will often
1366              * be the same as {@link #FIRST_YEAR}, but for compilation albums
1367              * they might differ.
1368              * <P>Type: INTEGER</P>
1369              */
1370             public static final String LAST_YEAR = "maxyear";
1371 
1372             /**
1373              * A non human readable key calculated from the ALBUM, used for
1374              * searching, sorting and grouping
1375              * <P>Type: TEXT</P>
1376              */
1377             public static final String ALBUM_KEY = "album_key";
1378 
1379             /**
1380              * Cached album art.
1381              * <P>Type: TEXT</P>
1382              */
1383             public static final String ALBUM_ART = "album_art";
1384         }
1385 
1386         /**
1387          * Contains artists for audio files
1388          */
1389         public static final class Albums implements BaseColumns, AlbumColumns {
1390             /**
1391              * Get the content:// style URI for the albums table on the
1392              * given volume.
1393              *
1394              * @param volumeName the name of the volume to get the URI for
1395              * @return the URI to the audio albums table on the given volume
1396              */
getContentUri(String volumeName)1397             public static Uri getContentUri(String volumeName) {
1398                 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1399                         "/audio/albums");
1400             }
1401 
1402             /**
1403              * The content:// style URI for the internal storage.
1404              */
1405             public static final Uri INTERNAL_CONTENT_URI =
1406                     getContentUri("internal");
1407 
1408             /**
1409              * The content:// style URI for the "primary" external storage
1410              * volume.
1411              */
1412             public static final Uri EXTERNAL_CONTENT_URI =
1413                     getContentUri("external");
1414 
1415             /**
1416              * The MIME type for this table.
1417              */
1418             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/albums";
1419 
1420             /**
1421              * The MIME type for entries in this table.
1422              */
1423             public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/album";
1424 
1425             /**
1426              * The default sort order for this table
1427              */
1428             public static final String DEFAULT_SORT_ORDER = ALBUM_KEY;
1429         }
1430     }
1431 
1432     public static final class Video {
1433 
1434         /**
1435          * The default sort order for this table.
1436          */
1437         public static final String DEFAULT_SORT_ORDER = MediaColumns.DISPLAY_NAME;
1438 
query(ContentResolver cr, Uri uri, String[] projection)1439         public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
1440             return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
1441         }
1442 
1443         public interface VideoColumns extends MediaColumns {
1444 
1445             /**
1446              * The duration of the video file, in ms
1447              * <P>Type: INTEGER (long)</P>
1448              */
1449             public static final String DURATION = "duration";
1450 
1451             /**
1452              * The artist who created the video file, if any
1453              * <P>Type: TEXT</P>
1454              */
1455             public static final String ARTIST = "artist";
1456 
1457             /**
1458              * The album the video file is from, if any
1459              * <P>Type: TEXT</P>
1460              */
1461             public static final String ALBUM = "album";
1462 
1463             /**
1464              * The resolution of the video file, formatted as "XxY"
1465              * <P>Type: TEXT</P>
1466              */
1467             public static final String RESOLUTION = "resolution";
1468 
1469             /**
1470              * The description of the video recording
1471              * <P>Type: TEXT</P>
1472              */
1473             public static final String DESCRIPTION = "description";
1474 
1475             /**
1476              * Whether the video should be published as public or private
1477              * <P>Type: INTEGER</P>
1478              */
1479             public static final String IS_PRIVATE = "isprivate";
1480 
1481             /**
1482              * The user-added tags associated with a video
1483              * <P>Type: TEXT</P>
1484              */
1485             public static final String TAGS = "tags";
1486 
1487             /**
1488              * The YouTube category of the video
1489              * <P>Type: TEXT</P>
1490              */
1491             public static final String CATEGORY = "category";
1492 
1493             /**
1494              * The language of the video
1495              * <P>Type: TEXT</P>
1496              */
1497             public static final String LANGUAGE = "language";
1498 
1499             /**
1500              * The latitude where the image was captured.
1501              * <P>Type: DOUBLE</P>
1502              */
1503             public static final String LATITUDE = "latitude";
1504 
1505             /**
1506              * The longitude where the image was captured.
1507              * <P>Type: DOUBLE</P>
1508              */
1509             public static final String LONGITUDE = "longitude";
1510 
1511             /**
1512              * The date & time that the image was taken in units
1513              * of milliseconds since jan 1, 1970.
1514              * <P>Type: INTEGER</P>
1515              */
1516             public static final String DATE_TAKEN = "datetaken";
1517 
1518             /**
1519              * The mini thumb id.
1520              * <P>Type: INTEGER</P>
1521              */
1522             public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
1523 
1524             /**
1525              * The bucket id of the video. This is a read-only property that
1526              * is automatically computed from the DATA column.
1527              * <P>Type: TEXT</P>
1528              */
1529             public static final String BUCKET_ID = "bucket_id";
1530 
1531             /**
1532              * The bucket display name of the video. This is a read-only property that
1533              * is automatically computed from the DATA column.
1534              * <P>Type: TEXT</P>
1535              */
1536             public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
1537 
1538             /**
1539              * The bookmark for the video. Time in ms. Represents the location in the video that the
1540              * video should start playing at the next time it is opened. If the value is null or
1541              * out of the range 0..DURATION-1 then the video should start playing from the
1542              * beginning.
1543              * <P>Type: INTEGER</P>
1544              */
1545             public static final String BOOKMARK = "bookmark";
1546         }
1547 
1548         public static final class Media implements VideoColumns {
1549             /**
1550              * Get the content:// style URI for the video media table on the
1551              * given volume.
1552              *
1553              * @param volumeName the name of the volume to get the URI for
1554              * @return the URI to the video media table on the given volume
1555              */
getContentUri(String volumeName)1556             public static Uri getContentUri(String volumeName) {
1557                 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1558                         "/video/media");
1559             }
1560 
1561             /**
1562              * The content:// style URI for the internal storage.
1563              */
1564             public static final Uri INTERNAL_CONTENT_URI =
1565                     getContentUri("internal");
1566 
1567             /**
1568              * The content:// style URI for the "primary" external storage
1569              * volume.
1570              */
1571             public static final Uri EXTERNAL_CONTENT_URI =
1572                     getContentUri("external");
1573 
1574             /**
1575              * The MIME type for this table.
1576              */
1577             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/video";
1578 
1579             /**
1580              * The default sort order for this table
1581              */
1582             public static final String DEFAULT_SORT_ORDER = TITLE;
1583         }
1584 
1585         /**
1586          * This class allows developers to query and get two kinds of thumbnails:
1587          * MINI_KIND: 512 x 384 thumbnail
1588          * MICRO_KIND: 96 x 96 thumbnail
1589          *
1590          */
1591         public static class Thumbnails implements BaseColumns {
1592             /**
1593              * This method cancels the thumbnail request so clients waiting for getThumbnail will be
1594              * interrupted and return immediately. Only the original process which made the getThumbnail
1595              * requests can cancel their own requests.
1596              *
1597              * @param cr ContentResolver
1598              * @param origId original video id
1599              */
cancelThumbnailRequest(ContentResolver cr, long origId)1600             public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
1601                 InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI);
1602             }
1603 
1604             /**
1605              * This method checks if the thumbnails of the specified image (origId) has been created.
1606              * It will be blocked until the thumbnails are generated.
1607              *
1608              * @param cr ContentResolver used to dispatch queries to MediaProvider.
1609              * @param origId Original image id associated with thumbnail of interest.
1610              * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND
1611              * @param options this is only used for MINI_KIND when decoding the Bitmap
1612              * @return A Bitmap instance. It could be null if the original image associated with
1613              *         origId doesn't exist or memory is not enough.
1614              */
getThumbnail(ContentResolver cr, long origId, int kind, BitmapFactory.Options options)1615             public static Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
1616                     BitmapFactory.Options options) {
1617                 return InternalThumbnails.getThumbnail(cr, origId, kind, options,
1618                         EXTERNAL_CONTENT_URI, true);
1619             }
1620 
1621             /**
1622              * Get the content:// style URI for the image media table on the
1623              * given volume.
1624              *
1625              * @param volumeName the name of the volume to get the URI for
1626              * @return the URI to the image media table on the given volume
1627              */
getContentUri(String volumeName)1628             public static Uri getContentUri(String volumeName) {
1629                 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1630                         "/video/thumbnails");
1631             }
1632 
1633             /**
1634              * The content:// style URI for the internal storage.
1635              */
1636             public static final Uri INTERNAL_CONTENT_URI =
1637                     getContentUri("internal");
1638 
1639             /**
1640              * The content:// style URI for the "primary" external storage
1641              * volume.
1642              */
1643             public static final Uri EXTERNAL_CONTENT_URI =
1644                     getContentUri("external");
1645 
1646             /**
1647              * The default sort order for this table
1648              */
1649             public static final String DEFAULT_SORT_ORDER = "video_id ASC";
1650 
1651             /**
1652              * The data stream for the thumbnail
1653              * <P>Type: DATA STREAM</P>
1654              */
1655             public static final String DATA = "_data";
1656 
1657             /**
1658              * The original image for the thumbnal
1659              * <P>Type: INTEGER (ID from Video table)</P>
1660              */
1661             public static final String VIDEO_ID = "video_id";
1662 
1663             /**
1664              * The kind of the thumbnail
1665              * <P>Type: INTEGER (One of the values below)</P>
1666              */
1667             public static final String KIND = "kind";
1668 
1669             public static final int MINI_KIND = 1;
1670             public static final int FULL_SCREEN_KIND = 2;
1671             public static final int MICRO_KIND = 3;
1672 
1673             /**
1674              * The width of the thumbnal
1675              * <P>Type: INTEGER (long)</P>
1676              */
1677             public static final String WIDTH = "width";
1678 
1679             /**
1680              * The height of the thumbnail
1681              * <P>Type: INTEGER (long)</P>
1682              */
1683             public static final String HEIGHT = "height";
1684         }
1685     }
1686 
1687     /**
1688      * Uri for querying the state of the media scanner.
1689      */
getMediaScannerUri()1690     public static Uri getMediaScannerUri() {
1691         return Uri.parse(CONTENT_AUTHORITY_SLASH + "none/media_scanner");
1692     }
1693 
1694     /**
1695      * Name of current volume being scanned by the media scanner.
1696      */
1697     public static final String MEDIA_SCANNER_VOLUME = "volume";
1698 }
1699