blob: 3bc1348bb2e9295a1aedcc887e4c66d07feb30c9 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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;
Marco Nelissen3822f732011-02-03 10:59:30 -080024import android.content.Context;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.database.Cursor;
26import android.database.DatabaseUtils;
Ray Chen00c575a2009-08-28 14:12:15 -070027import android.database.sqlite.SQLiteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.graphics.Bitmap;
29import android.graphics.BitmapFactory;
30import android.graphics.Matrix;
Ray Chen00c575a2009-08-28 14:12:15 -070031import android.media.MiniThumbFile;
Ray Chenbf124e72010-01-26 14:43:35 -080032import android.media.ThumbnailUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.net.Uri;
34import android.os.Environment;
Ray Chen00c575a2009-08-28 14:12:15 -070035import android.os.ParcelFileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.util.Log;
37
38import java.io.FileInputStream;
39import java.io.FileNotFoundException;
40import java.io.IOException;
41import java.io.InputStream;
42import java.io.OutputStream;
43import java.io.UnsupportedEncodingException;
44import java.text.Collator;
45
46/**
47 * The Media provider contains meta data for all available media on both internal
48 * and external storage devices.
49 */
Ray Chen00c575a2009-08-28 14:12:15 -070050public final class MediaStore {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051 private final static String TAG = "MediaStore";
52
53 public static final String AUTHORITY = "media";
54
55 private static final String CONTENT_AUTHORITY_SLASH = "content://" + AUTHORITY + "/";
56
Mike Lockwooda3156052010-11-20 12:28:27 -050057 /**
58 * Broadcast Action: A broadcast to indicate the end of an MTP session with the host.
59 * This broadcast is only sent if MTP activity has modified the media database during the
60 * most recent MTP session.
Mike Lockwoode2228722011-01-19 16:07:25 -080061 *
62 * @hide
Mike Lockwooda3156052010-11-20 12:28:27 -050063 */
64 public static final String ACTION_MTP_SESSION_END = "android.provider.action.MTP_SESSION_END";
65
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066 /**
Daniel Sandleredcdbb62010-02-18 16:00:43 -050067 * Activity Action: Launch a music player.
68 * The activity should be able to play, browse, or manipulate music files stored on the device.
69 */
70 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
71 public static final String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
72
73 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 * Activity Action: Perform a search for media.
75 * Contains at least the {@link android.app.SearchManager#QUERY} extra.
76 * May also contain any combination of the following extras:
77 * EXTRA_MEDIA_ARTIST, EXTRA_MEDIA_ALBUM, EXTRA_MEDIA_TITLE, EXTRA_MEDIA_FOCUS
78 *
79 * @see android.provider.MediaStore#EXTRA_MEDIA_ARTIST
80 * @see android.provider.MediaStore#EXTRA_MEDIA_ALBUM
81 * @see android.provider.MediaStore#EXTRA_MEDIA_TITLE
82 * @see android.provider.MediaStore#EXTRA_MEDIA_FOCUS
83 */
84 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
85 public static final String INTENT_ACTION_MEDIA_SEARCH = "android.intent.action.MEDIA_SEARCH";
86
87 /**
Mike LeBeau2fe6fd02010-09-08 19:10:17 -040088 * An intent to perform a search for music media and automatically play content from the
89 * result when possible. This can be fired, for example, by the result of a voice recognition
90 * command to listen to music.
91 * <p>
92 * Contains the {@link android.app.SearchManager#QUERY} extra, which is a string
93 * that can contain any type of unstructured music search, like the name of an artist,
94 * an album, a song, a genre, or any combination of these.
95 * <p>
96 * Because this intent includes an open-ended unstructured search string, it makes the most
97 * sense for apps that can support large-scale search of music, such as services connected
98 * to an online database of music which can be streamed and played on the device.
99 */
100 public static final String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH =
101 "android.media.action.MEDIA_PLAY_FROM_SEARCH";
102
103 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 * The name of the Intent-extra used to define the artist
105 */
106 public static final String EXTRA_MEDIA_ARTIST = "android.intent.extra.artist";
107 /**
108 * The name of the Intent-extra used to define the album
109 */
110 public static final String EXTRA_MEDIA_ALBUM = "android.intent.extra.album";
111 /**
112 * The name of the Intent-extra used to define the song title
113 */
114 public static final String EXTRA_MEDIA_TITLE = "android.intent.extra.title";
115 /**
116 * The name of the Intent-extra used to define the search focus. The search focus
117 * indicates whether the search should be for things related to the artist, album
118 * or song that is identified by the other extras.
119 */
120 public static final String EXTRA_MEDIA_FOCUS = "android.intent.extra.focus";
121
122 /**
123 * The name of the Intent-extra used to control the orientation of a ViewImage or a MovieView.
124 * This is an int property that overrides the activity's requestedOrientation.
125 * @see android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
126 */
127 public static final String EXTRA_SCREEN_ORIENTATION = "android.intent.extra.screenOrientation";
128
129 /**
130 * The name of an Intent-extra used to control the UI of a ViewImage.
131 * This is a boolean property that overrides the activity's default fullscreen state.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 */
133 public static final String EXTRA_FULL_SCREEN = "android.intent.extra.fullScreen";
134
135 /**
136 * The name of an Intent-extra used to control the UI of a ViewImage.
137 * This is a boolean property that specifies whether or not to show action icons.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 */
139 public static final String EXTRA_SHOW_ACTION_ICONS = "android.intent.extra.showActionIcons";
140
141 /**
142 * The name of the Intent-extra used to control the onCompletion behavior of a MovieView.
143 * This is a boolean property that specifies whether or not to finish the MovieView activity
144 * when the movie completes playing. The default value is true, which means to automatically
145 * exit the movie player activity when the movie completes playing.
146 */
147 public static final String EXTRA_FINISH_ON_COMPLETION = "android.intent.extra.finishOnCompletion";
148
149 /**
150 * The name of the Intent action used to launch a camera in still image mode.
151 */
152 public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
153
154 /**
155 * The name of the Intent action used to launch a camera in video mode.
156 */
157 public static final String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
158
159 /**
160 * Standard Intent action that can be sent to have the camera application
161 * capture an image and return it.
162 * <p>
163 * The caller may pass an extra EXTRA_OUTPUT to control where this image will be written.
164 * If the EXTRA_OUTPUT is not present, then a small sized image is returned as a Bitmap
165 * object in the extra field. This is useful for applications that only need a small image.
166 * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri
167 * value of EXTRA_OUTPUT.
168 * @see #EXTRA_OUTPUT
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 */
170 public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
171
172 /**
173 * Standard Intent action that can be sent to have the camera application
174 * capture an video and return it.
175 * <p>
176 * The caller may pass in an extra EXTRA_VIDEO_QUALITY to control the video quality.
177 * <p>
178 * The caller may pass in an extra EXTRA_OUTPUT to control
179 * where the video is written. If EXTRA_OUTPUT is not present the video will be
180 * written to the standard location for videos, and the Uri of that location will be
181 * returned in the data field of the Uri.
182 * @see #EXTRA_OUTPUT
Wu-cheng Lie7bc7462011-03-16 17:18:58 +0800183 * @see #EXTRA_VIDEO_QUALITY
184 * @see #EXTRA_SIZE_LIMIT
185 * @see #EXTRA_DURATION_LIMIT
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 */
187 public final static String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
188
189 /**
190 * The name of the Intent-extra used to control the quality of a recorded video. This is an
191 * integer property. Currently value 0 means low quality, suitable for MMS messages, and
192 * value 1 means high quality. In the future other quality levels may be added.
193 */
194 public final static String EXTRA_VIDEO_QUALITY = "android.intent.extra.videoQuality";
195
196 /**
197 * Specify the maximum allowed size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 */
199 public final static String EXTRA_SIZE_LIMIT = "android.intent.extra.sizeLimit";
200
201 /**
Chih-Chung Changeb0098d2009-08-25 12:59:54 +0800202 * Specify the maximum allowed recording duration in seconds.
Chih-Chung Changeb0098d2009-08-25 12:59:54 +0800203 */
204 public final static String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
205
206 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 * The name of the Intent-extra used to indicate a content resolver Uri to be used to
208 * store the requested image or video.
209 */
210 public final static String EXTRA_OUTPUT = "output";
211
212 /**
Marco Nelissened297a82010-01-04 13:24:31 -0800213 * The string that is used when a media attribute is not known. For example,
214 * if an audio file does not have any meta data, the artist and album columns
215 * will be set to this value.
Marco Nelissened297a82010-01-04 13:24:31 -0800216 */
217 public static final String UNKNOWN_STRING = "<unknown>";
218
219 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 * Common fields for most MediaProvider tables
221 */
222
Ray Chen00c575a2009-08-28 14:12:15 -0700223 public interface MediaColumns extends BaseColumns {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 /**
225 * The data stream for the file
226 * <P>Type: DATA STREAM</P>
227 */
228 public static final String DATA = "_data";
229
230 /**
231 * The size of the file in bytes
232 * <P>Type: INTEGER (long)</P>
233 */
234 public static final String SIZE = "_size";
235
236 /**
237 * The display name of the file
238 * <P>Type: TEXT</P>
239 */
240 public static final String DISPLAY_NAME = "_display_name";
241
242 /**
243 * The title of the content
244 * <P>Type: TEXT</P>
245 */
246 public static final String TITLE = "title";
247
248 /**
249 * The time the file was added to the media provider
250 * Units are seconds since 1970.
251 * <P>Type: INTEGER (long)</P>
252 */
253 public static final String DATE_ADDED = "date_added";
254
255 /**
256 * The time the file was last modified
257 * Units are seconds since 1970.
258 * NOTE: This is for internal use by the media scanner. Do not modify this field.
259 * <P>Type: INTEGER (long)</P>
260 */
261 public static final String DATE_MODIFIED = "date_modified";
262
263 /**
264 * The MIME type of the file
265 * <P>Type: TEXT</P>
266 */
267 public static final String MIME_TYPE = "mime_type";
Mike Lockwoodd815f792010-07-12 08:49:01 -0400268
269 /**
Mike Lockwoodcbaea352010-07-17 08:34:17 -0400270 * The MTP object handle of a newly transfered file.
271 * Used to pass the new file's object handle through the media scanner
272 * from MTP to the media provider
273 * For internal use only by MTP, media scanner and media provider.
274 * <P>Type: INTEGER</P>
275 * @hide
276 */
277 public static final String MEDIA_SCANNER_NEW_OBJECT_ID = "media_scanner_new_object_id";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 }
279
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400280 /**
Mike Lockwood0b20b772010-11-04 13:16:48 -0400281 * Media provider table containing an index of all files in the media storage,
282 * including non-media files. This should be used by applications that work with
283 * non-media file types (text, HTML, PDF, etc) as well as applications that need to
284 * work with multiple media file types in a single query.
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400285 */
Mike Lockwood3b2a62e2010-09-08 12:47:57 -0400286 public static final class Files {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400287
Mike Lockwood0b20b772010-11-04 13:16:48 -0400288 /**
289 * Get the content:// style URI for the files table on the
290 * given volume.
291 *
292 * @param volumeName the name of the volume to get the URI for
293 * @return the URI to the files table on the given volume
294 */
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400295 public static Uri getContentUri(String volumeName) {
296 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
Mike Lockwood3b2a62e2010-09-08 12:47:57 -0400297 "/file");
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400298 }
299
Mike Lockwood0b20b772010-11-04 13:16:48 -0400300 /**
301 * Get the content:// style URI for a single row in the files table on the
302 * given volume.
303 *
304 * @param volumeName the name of the volume to get the URI for
305 * @param rowId the file to get the URI for
306 * @return the URI to the files table on the given volume
307 */
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400308 public static final Uri getContentUri(String volumeName,
Mike Lockwood0b20b772010-11-04 13:16:48 -0400309 long rowId) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400310 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
Mike Lockwood0b20b772010-11-04 13:16:48 -0400311 + "/file/" + rowId);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400312 }
313
Mike Lockwood0b20b772010-11-04 13:16:48 -0400314 /**
315 * For use only by the MTP implementation.
316 * @hide
317 */
Mike Lockwood8490e662010-09-09 14:16:22 -0400318 public static Uri getMtpObjectsUri(String volumeName) {
319 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
320 "/object");
321 }
322
Mike Lockwood0b20b772010-11-04 13:16:48 -0400323 /**
324 * For use only by the MTP implementation.
325 * @hide
326 */
Mike Lockwood8490e662010-09-09 14:16:22 -0400327 public static final Uri getMtpObjectsUri(String volumeName,
Mike Lockwood3b2a62e2010-09-08 12:47:57 -0400328 long fileId) {
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400329 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
Mike Lockwood8490e662010-09-09 14:16:22 -0400330 + "/object/" + fileId);
331 }
332
Mike Lockwood0b20b772010-11-04 13:16:48 -0400333 /**
334 * Used to implement the MTP GetObjectReferences and SetObjectReferences commands.
335 * @hide
336 */
Mike Lockwood8490e662010-09-09 14:16:22 -0400337 public static final Uri getMtpReferencesUri(String volumeName,
338 long fileId) {
339 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
340 + "/object/" + fileId + "/references");
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400341 }
342
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400343 /**
344 * Fields for master table for all media files.
345 * Table also contains MediaColumns._ID, DATA, SIZE and DATE_MODIFIED.
346 */
Mike Lockwood3b2a62e2010-09-08 12:47:57 -0400347 public interface FileColumns extends MediaColumns {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400348 /**
Mike Lockwoodb239b6832011-04-05 10:21:27 -0400349 * The MTP storage ID of the file
350 * <P>Type: INTEGER</P>
351 * @hide
352 */
353 public static final String STORAGE_ID = "storage_id";
354
355 /**
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400356 * The MTP format code of the file
357 * <P>Type: INTEGER</P>
Mike Lockwood0b20b772010-11-04 13:16:48 -0400358 * @hide
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400359 */
360 public static final String FORMAT = "format";
361
362 /**
363 * The index of the parent directory of the file
364 * <P>Type: INTEGER</P>
365 */
366 public static final String PARENT = "parent";
Mike Lockwoodfed16172010-07-09 10:46:02 -0400367
368 /**
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400369 * The MIME type of the file
370 * <P>Type: TEXT</P>
Mike Lockwoodfed16172010-07-09 10:46:02 -0400371 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400372 public static final String MIME_TYPE = "mime_type";
Mike Lockwoodfed16172010-07-09 10:46:02 -0400373
374 /**
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400375 * The title of the content
376 * <P>Type: TEXT</P>
Mike Lockwoodfed16172010-07-09 10:46:02 -0400377 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400378 public static final String TITLE = "title";
379
380 /**
381 * The media type (audio, video, image or playlist)
382 * of the file, or 0 for not a media file
383 * <P>Type: TEXT</P>
384 */
385 public static final String MEDIA_TYPE = "media_type";
386
387 /**
Mike Lockwooded723b42011-01-26 15:57:07 -0800388 * Constant for the {@link #MEDIA_TYPE} column indicating that file
389 * is not an audio, image, video or playlist file.
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400390 */
391 public static final int MEDIA_TYPE_NONE = 0;
Mike Lockwooded723b42011-01-26 15:57:07 -0800392
393 /**
394 * Constant for the {@link #MEDIA_TYPE} column indicating that file is an image file.
395 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400396 public static final int MEDIA_TYPE_IMAGE = 1;
Mike Lockwooded723b42011-01-26 15:57:07 -0800397
398 /**
399 * Constant for the {@link #MEDIA_TYPE} column indicating that file is an audio file.
400 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400401 public static final int MEDIA_TYPE_AUDIO = 2;
Mike Lockwooded723b42011-01-26 15:57:07 -0800402
403 /**
404 * Constant for the {@link #MEDIA_TYPE} column indicating that file is an video file.
405 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400406 public static final int MEDIA_TYPE_VIDEO = 3;
Mike Lockwooded723b42011-01-26 15:57:07 -0800407
408 /**
409 * Constant for the {@link #MEDIA_TYPE} column indicating that file is an playlist file.
410 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400411 public static final int MEDIA_TYPE_PLAYLIST = 4;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400412 }
413 }
414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 /**
Ray Chen00c575a2009-08-28 14:12:15 -0700416 * This class is used internally by Images.Thumbnails and Video.Thumbnails, it's not intended
417 * to be accessed elsewhere.
418 */
419 private static class InternalThumbnails implements BaseColumns {
420 private static final int MINI_KIND = 1;
421 private static final int FULL_SCREEN_KIND = 2;
422 private static final int MICRO_KIND = 3;
423 private static final String[] PROJECTION = new String[] {_ID, MediaColumns.DATA};
Ray Chen13ed5752009-10-05 12:21:24 -0700424 static final int DEFAULT_GROUP_ID = 0;
Chih-Chung Chang2ca36192010-08-24 19:25:56 +0800425 private static final Object sThumbBufLock = new Object();
426 private static byte[] sThumbBuf;
Ray Chen00c575a2009-08-28 14:12:15 -0700427
Ray Chenf9a243d2009-10-29 18:15:29 -0700428 private static Bitmap getMiniThumbFromFile(Cursor c, Uri baseUri, ContentResolver cr, BitmapFactory.Options options) {
429 Bitmap bitmap = null;
430 Uri thumbUri = null;
431 try {
432 long thumbId = c.getLong(0);
433 String filePath = c.getString(1);
434 thumbUri = ContentUris.withAppendedId(baseUri, thumbId);
435 ParcelFileDescriptor pfdInput = cr.openFileDescriptor(thumbUri, "r");
436 bitmap = BitmapFactory.decodeFileDescriptor(
437 pfdInput.getFileDescriptor(), null, options);
438 pfdInput.close();
439 } catch (FileNotFoundException ex) {
440 Log.e(TAG, "couldn't open thumbnail " + thumbUri + "; " + ex);
441 } catch (IOException ex) {
442 Log.e(TAG, "couldn't open thumbnail " + thumbUri + "; " + ex);
443 } catch (OutOfMemoryError ex) {
444 Log.e(TAG, "failed to allocate memory for thumbnail "
445 + thumbUri + "; " + ex);
446 }
447 return bitmap;
448 }
449
Ray Chen00c575a2009-08-28 14:12:15 -0700450 /**
Ray Chenb9944192009-09-29 20:24:01 -0700451 * This method cancels the thumbnail request so clients waiting for getThumbnail will be
452 * interrupted and return immediately. Only the original process which made the getThumbnail
453 * requests can cancel their own requests.
454 *
455 * @param cr ContentResolver
Ray Chenef093cd2009-09-29 19:38:58 -0700456 * @param origId original image or video id. use -1 to cancel all requests.
Ray Chen13ed5752009-10-05 12:21:24 -0700457 * @param groupId the same groupId used in getThumbnail
Ray Chenb9944192009-09-29 20:24:01 -0700458 * @param baseUri the base URI of requested thumbnails
459 */
Ray Chen13ed5752009-10-05 12:21:24 -0700460 static void cancelThumbnailRequest(ContentResolver cr, long origId, Uri baseUri,
461 long groupId) {
Ray Chenb9944192009-09-29 20:24:01 -0700462 Uri cancelUri = baseUri.buildUpon().appendQueryParameter("cancel", "1")
Ray Chen13ed5752009-10-05 12:21:24 -0700463 .appendQueryParameter("orig_id", String.valueOf(origId))
464 .appendQueryParameter("group_id", String.valueOf(groupId)).build();
Ray Chenb9944192009-09-29 20:24:01 -0700465 Cursor c = null;
466 try {
467 c = cr.query(cancelUri, PROJECTION, null, null, null);
468 }
469 finally {
470 if (c != null) c.close();
471 }
472 }
473 /**
Ray Chen00c575a2009-08-28 14:12:15 -0700474 * This method ensure thumbnails associated with origId are generated and decode the byte
475 * stream from database (MICRO_KIND) or file (MINI_KIND).
476 *
477 * Special optimization has been done to avoid further IPC communication for MICRO_KIND
478 * thumbnails.
479 *
480 * @param cr ContentResolver
481 * @param origId original image or video id
482 * @param kind could be MINI_KIND or MICRO_KIND
483 * @param options this is only used for MINI_KIND when decoding the Bitmap
484 * @param baseUri the base URI of requested thumbnails
Ray Chen13ed5752009-10-05 12:21:24 -0700485 * @param groupId the id of group to which this request belongs
Ray Chen00c575a2009-08-28 14:12:15 -0700486 * @return Bitmap bitmap of specified thumbnail kind
487 */
Ray Chen13ed5752009-10-05 12:21:24 -0700488 static Bitmap getThumbnail(ContentResolver cr, long origId, long groupId, int kind,
Ray Chen00c575a2009-08-28 14:12:15 -0700489 BitmapFactory.Options options, Uri baseUri, boolean isVideo) {
490 Bitmap bitmap = null;
491 String filePath = null;
Ray Chenb9944192009-09-29 20:24:01 -0700492 // Log.v(TAG, "getThumbnail: origId="+origId+", kind="+kind+", isVideo="+isVideo);
Ray Chenf9a243d2009-10-29 18:15:29 -0700493 // If the magic is non-zero, we simply return thumbnail if it does exist.
Ray Chen00c575a2009-08-28 14:12:15 -0700494 // querying MediaProvider and simply return thumbnail.
Ray Chen1ba38b62010-05-14 13:50:04 -0700495 MiniThumbFile thumbFile = new MiniThumbFile(isVideo ? Video.Media.EXTERNAL_CONTENT_URI
496 : Images.Media.EXTERNAL_CONTENT_URI);
497 Cursor c = null;
498 try {
499 long magic = thumbFile.getMagic(origId);
500 if (magic != 0) {
501 if (kind == MICRO_KIND) {
Chih-Chung Chang94392412010-08-25 15:54:51 +0800502 synchronized (sThumbBufLock) {
503 if (sThumbBuf == null) {
504 sThumbBuf = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
505 }
506 if (thumbFile.getMiniThumbFromFile(origId, sThumbBuf) != null) {
507 bitmap = BitmapFactory.decodeByteArray(sThumbBuf, 0, sThumbBuf.length);
508 if (bitmap == null) {
509 Log.w(TAG, "couldn't decode byte array.");
510 }
Ray Chen1ba38b62010-05-14 13:50:04 -0700511 }
Ray Chen00c575a2009-08-28 14:12:15 -0700512 }
Ray Chen1ba38b62010-05-14 13:50:04 -0700513 return bitmap;
514 } else if (kind == MINI_KIND) {
515 String column = isVideo ? "video_id=" : "image_id=";
Ray Chenf9a243d2009-10-29 18:15:29 -0700516 c = cr.query(baseUri, PROJECTION, column + origId, null, null);
517 if (c != null && c.moveToFirst()) {
518 bitmap = getMiniThumbFromFile(c, baseUri, cr, options);
519 if (bitmap != null) {
520 return bitmap;
521 }
522 }
Ray Chenf9a243d2009-10-29 18:15:29 -0700523 }
Ray Chen00c575a2009-08-28 14:12:15 -0700524 }
Ray Chen00c575a2009-08-28 14:12:15 -0700525
Ray Chen00c575a2009-08-28 14:12:15 -0700526 Uri blockingUri = baseUri.buildUpon().appendQueryParameter("blocking", "1")
Ray Chen13ed5752009-10-05 12:21:24 -0700527 .appendQueryParameter("orig_id", String.valueOf(origId))
528 .appendQueryParameter("group_id", String.valueOf(groupId)).build();
Ray Chen1ba38b62010-05-14 13:50:04 -0700529 if (c != null) c.close();
Ray Chen00c575a2009-08-28 14:12:15 -0700530 c = cr.query(blockingUri, PROJECTION, null, null, null);
531 // This happens when original image/video doesn't exist.
532 if (c == null) return null;
533
534 // Assuming thumbnail has been generated, at least original image exists.
535 if (kind == MICRO_KIND) {
Chih-Chung Chang2ca36192010-08-24 19:25:56 +0800536 synchronized (sThumbBufLock) {
537 if (sThumbBuf == null) {
538 sThumbBuf = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
539 }
540 if (thumbFile.getMiniThumbFromFile(origId, sThumbBuf) != null) {
541 bitmap = BitmapFactory.decodeByteArray(sThumbBuf, 0, sThumbBuf.length);
542 if (bitmap == null) {
543 Log.w(TAG, "couldn't decode byte array.");
544 }
Ray Chen00c575a2009-08-28 14:12:15 -0700545 }
546 }
547 } else if (kind == MINI_KIND) {
548 if (c.moveToFirst()) {
Ray Chenf9a243d2009-10-29 18:15:29 -0700549 bitmap = getMiniThumbFromFile(c, baseUri, cr, options);
Ray Chen00c575a2009-08-28 14:12:15 -0700550 }
551 } else {
552 throw new IllegalArgumentException("Unsupported kind: " + kind);
553 }
554
555 // We probably run out of space, so create the thumbnail in memory.
556 if (bitmap == null) {
Ray Chen44dcf652010-04-05 11:26:40 -0700557 Log.v(TAG, "Create the thumbnail in memory: origId=" + origId
558 + ", kind=" + kind + ", isVideo="+isVideo);
Ray Chen00c575a2009-08-28 14:12:15 -0700559 Uri uri = Uri.parse(
560 baseUri.buildUpon().appendPath(String.valueOf(origId))
561 .toString().replaceFirst("thumbnails", "media"));
Ray Chenef093cd2009-09-29 19:38:58 -0700562 if (filePath == null) {
Marco Nelissen9b150b72009-09-30 16:39:15 -0700563 if (c != null) c.close();
Ray Chen00c575a2009-08-28 14:12:15 -0700564 c = cr.query(uri, PROJECTION, null, null, null);
Ray Chenef093cd2009-09-29 19:38:58 -0700565 if (c == null || !c.moveToFirst()) {
566 return null;
567 }
568 filePath = c.getString(1);
569 }
570 if (isVideo) {
Ray Chen44dcf652010-04-05 11:26:40 -0700571 bitmap = ThumbnailUtils.createVideoThumbnail(filePath, kind);
Ray Chen00c575a2009-08-28 14:12:15 -0700572 } else {
Ray Chen44dcf652010-04-05 11:26:40 -0700573 bitmap = ThumbnailUtils.createImageThumbnail(filePath, kind);
Ray Chen00c575a2009-08-28 14:12:15 -0700574 }
575 }
576 } catch (SQLiteException ex) {
577 Log.w(TAG, ex);
578 } finally {
579 if (c != null) c.close();
Ray Chen1ba38b62010-05-14 13:50:04 -0700580 // To avoid file descriptor leak in application process.
581 thumbFile.deactivate();
582 thumbFile = null;
Ray Chen00c575a2009-08-28 14:12:15 -0700583 }
584 return bitmap;
585 }
586 }
587
588 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 * Contains meta data for all available images.
590 */
Ray Chen00c575a2009-08-28 14:12:15 -0700591 public static final class Images {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 public interface ImageColumns extends MediaColumns {
593 /**
594 * The description of the image
595 * <P>Type: TEXT</P>
596 */
597 public static final String DESCRIPTION = "description";
598
599 /**
600 * The picasa id of the image
601 * <P>Type: TEXT</P>
602 */
603 public static final String PICASA_ID = "picasa_id";
604
605 /**
606 * Whether the video should be published as public or private
607 * <P>Type: INTEGER</P>
608 */
609 public static final String IS_PRIVATE = "isprivate";
610
611 /**
612 * The latitude where the image was captured.
613 * <P>Type: DOUBLE</P>
614 */
615 public static final String LATITUDE = "latitude";
616
617 /**
618 * The longitude where the image was captured.
619 * <P>Type: DOUBLE</P>
620 */
621 public static final String LONGITUDE = "longitude";
622
623 /**
624 * The date & time that the image was taken in units
625 * of milliseconds since jan 1, 1970.
626 * <P>Type: INTEGER</P>
627 */
628 public static final String DATE_TAKEN = "datetaken";
629
630 /**
631 * The orientation for the image expressed as degrees.
632 * Only degrees 0, 90, 180, 270 will work.
633 * <P>Type: INTEGER</P>
634 */
635 public static final String ORIENTATION = "orientation";
636
637 /**
638 * The mini thumb id.
639 * <P>Type: INTEGER</P>
640 */
641 public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
642
643 /**
644 * The bucket id of the image. This is a read-only property that
645 * is automatically computed from the DATA column.
646 * <P>Type: TEXT</P>
647 */
648 public static final String BUCKET_ID = "bucket_id";
649
650 /**
651 * The bucket display name of the image. This is a read-only property that
652 * is automatically computed from the DATA column.
653 * <P>Type: TEXT</P>
654 */
655 public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
656 }
657
658 public static final class Media implements ImageColumns {
Ray Chen00c575a2009-08-28 14:12:15 -0700659 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
661 }
662
663 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection,
Ray Chen00c575a2009-08-28 14:12:15 -0700664 String where, String orderBy) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 return cr.query(uri, projection, where,
666 null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
667 }
668
669 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection,
Ray Chen00c575a2009-08-28 14:12:15 -0700670 String selection, String [] selectionArgs, String orderBy) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 return cr.query(uri, projection, selection,
672 selectionArgs, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
673 }
674
675 /**
676 * Retrieves an image for the given url as a {@link Bitmap}.
677 *
678 * @param cr The content resolver to use
679 * @param url The url of the image
680 * @throws FileNotFoundException
681 * @throws IOException
682 */
683 public static final Bitmap getBitmap(ContentResolver cr, Uri url)
Ray Chen00c575a2009-08-28 14:12:15 -0700684 throws FileNotFoundException, IOException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 InputStream input = cr.openInputStream(url);
686 Bitmap bitmap = BitmapFactory.decodeStream(input);
687 input.close();
688 return bitmap;
689 }
690
691 /**
692 * Insert an image and create a thumbnail for it.
693 *
694 * @param cr The content resolver to use
695 * @param imagePath The path to the image to insert
696 * @param name The name of the image
697 * @param description The description of the image
698 * @return The URL to the newly created image
699 * @throws FileNotFoundException
700 */
Ray Chen00c575a2009-08-28 14:12:15 -0700701 public static final String insertImage(ContentResolver cr, String imagePath,
702 String name, String description) throws FileNotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 // Check if file exists with a FileInputStream
704 FileInputStream stream = new FileInputStream(imagePath);
705 try {
Marco Nelissen2f189fa2009-06-30 10:32:00 -0700706 Bitmap bm = BitmapFactory.decodeFile(imagePath);
707 String ret = insertImage(cr, bm, name, description);
708 bm.recycle();
709 return ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 } finally {
711 try {
712 stream.close();
713 } catch (IOException e) {
714 }
715 }
716 }
717
718 private static final Bitmap StoreThumbnail(
719 ContentResolver cr,
720 Bitmap source,
721 long id,
722 float width, float height,
723 int kind) {
724 // create the matrix to scale it
725 Matrix matrix = new Matrix();
726
727 float scaleX = width / source.getWidth();
728 float scaleY = height / source.getHeight();
729
730 matrix.setScale(scaleX, scaleY);
731
732 Bitmap thumb = Bitmap.createBitmap(source, 0, 0,
733 source.getWidth(),
734 source.getHeight(), matrix,
735 true);
736
737 ContentValues values = new ContentValues(4);
738 values.put(Images.Thumbnails.KIND, kind);
739 values.put(Images.Thumbnails.IMAGE_ID, (int)id);
740 values.put(Images.Thumbnails.HEIGHT, thumb.getHeight());
741 values.put(Images.Thumbnails.WIDTH, thumb.getWidth());
742
743 Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values);
744
745 try {
746 OutputStream thumbOut = cr.openOutputStream(url);
747
748 thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut);
749 thumbOut.close();
750 return thumb;
751 }
752 catch (FileNotFoundException ex) {
753 return null;
754 }
755 catch (IOException ex) {
756 return null;
757 }
758 }
759
760 /**
761 * Insert an image and create a thumbnail for it.
762 *
763 * @param cr The content resolver to use
764 * @param source The stream to use for the image
765 * @param title The name of the image
766 * @param description The description of the image
767 * @return The URL to the newly created image, or <code>null</code> if the image failed to be stored
768 * for any reason.
769 */
770 public static final String insertImage(ContentResolver cr, Bitmap source,
Ray Chen00c575a2009-08-28 14:12:15 -0700771 String title, String description) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 ContentValues values = new ContentValues();
773 values.put(Images.Media.TITLE, title);
774 values.put(Images.Media.DESCRIPTION, description);
775 values.put(Images.Media.MIME_TYPE, "image/jpeg");
776
777 Uri url = null;
778 String stringUrl = null; /* value to be returned */
779
Ray Chen00c575a2009-08-28 14:12:15 -0700780 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781 url = cr.insert(EXTERNAL_CONTENT_URI, values);
782
783 if (source != null) {
784 OutputStream imageOut = cr.openOutputStream(url);
785 try {
786 source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut);
787 } finally {
788 imageOut.close();
789 }
790
791 long id = ContentUris.parseId(url);
Ray Chen44dcf652010-04-05 11:26:40 -0700792 // Wait until MINI_KIND thumbnail is generated.
793 Bitmap miniThumb = Images.Thumbnails.getThumbnail(cr, id,
794 Images.Thumbnails.MINI_KIND, null);
795 // This is for backward compatibility.
796 Bitmap microThumb = StoreThumbnail(cr, miniThumb, id, 50F, 50F,
797 Images.Thumbnails.MICRO_KIND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 } else {
799 Log.e(TAG, "Failed to create thumbnail, removing original");
800 cr.delete(url, null, null);
801 url = null;
802 }
803 } catch (Exception e) {
804 Log.e(TAG, "Failed to insert image", e);
805 if (url != null) {
806 cr.delete(url, null, null);
807 url = null;
808 }
809 }
810
811 if (url != null) {
812 stringUrl = url.toString();
813 }
814
815 return stringUrl;
816 }
817
818 /**
819 * Get the content:// style URI for the image media table on the
820 * given volume.
821 *
822 * @param volumeName the name of the volume to get the URI for
823 * @return the URI to the image media table on the given volume
824 */
825 public static Uri getContentUri(String volumeName) {
826 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
827 "/images/media");
828 }
829
830 /**
831 * The content:// style URI for the internal storage.
832 */
833 public static final Uri INTERNAL_CONTENT_URI =
834 getContentUri("internal");
835
836 /**
837 * The content:// style URI for the "primary" external storage
838 * volume.
839 */
840 public static final Uri EXTERNAL_CONTENT_URI =
841 getContentUri("external");
842
843 /**
844 * The MIME type of of this directory of
845 * images. Note that each entry in this directory will have a standard
846 * image MIME type as appropriate -- for example, image/jpeg.
847 */
848 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/image";
849
850 /**
851 * The default sort order for this table
852 */
853 public static final String DEFAULT_SORT_ORDER = ImageColumns.BUCKET_DISPLAY_NAME;
Ray Chen00c575a2009-08-28 14:12:15 -0700854 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855
Ray Chen00c575a2009-08-28 14:12:15 -0700856 /**
857 * This class allows developers to query and get two kinds of thumbnails:
858 * MINI_KIND: 512 x 384 thumbnail
859 * MICRO_KIND: 96 x 96 thumbnail
860 */
861 public static class Thumbnails implements BaseColumns {
862 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
864 }
865
Ray Chen00c575a2009-08-28 14:12:15 -0700866 public static final Cursor queryMiniThumbnails(ContentResolver cr, Uri uri, int kind,
867 String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 return cr.query(uri, projection, "kind = " + kind, null, DEFAULT_SORT_ORDER);
869 }
870
Ray Chen00c575a2009-08-28 14:12:15 -0700871 public static final Cursor queryMiniThumbnail(ContentResolver cr, long origId, int kind,
872 String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 return cr.query(EXTERNAL_CONTENT_URI, projection,
874 IMAGE_ID + " = " + origId + " AND " + KIND + " = " +
875 kind, null, null);
876 }
877
878 /**
Ray Chenb9944192009-09-29 20:24:01 -0700879 * This method cancels the thumbnail request so clients waiting for getThumbnail will be
880 * interrupted and return immediately. Only the original process which made the getThumbnail
881 * requests can cancel their own requests.
882 *
883 * @param cr ContentResolver
884 * @param origId original image id
885 */
886 public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
Ray Chen13ed5752009-10-05 12:21:24 -0700887 InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI,
888 InternalThumbnails.DEFAULT_GROUP_ID);
Ray Chenb9944192009-09-29 20:24:01 -0700889 }
890
891 /**
Ray Chen00c575a2009-08-28 14:12:15 -0700892 * This method checks if the thumbnails of the specified image (origId) has been created.
893 * It will be blocked until the thumbnails are generated.
894 *
895 * @param cr ContentResolver used to dispatch queries to MediaProvider.
896 * @param origId Original image id associated with thumbnail of interest.
897 * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND.
898 * @param options this is only used for MINI_KIND when decoding the Bitmap
899 * @return A Bitmap instance. It could be null if the original image
900 * associated with origId doesn't exist or memory is not enough.
901 */
902 public static Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
903 BitmapFactory.Options options) {
Ray Chen13ed5752009-10-05 12:21:24 -0700904 return InternalThumbnails.getThumbnail(cr, origId,
905 InternalThumbnails.DEFAULT_GROUP_ID, kind, options,
906 EXTERNAL_CONTENT_URI, false);
907 }
908
909 /**
910 * This method cancels the thumbnail request so clients waiting for getThumbnail will be
911 * interrupted and return immediately. Only the original process which made the getThumbnail
912 * requests can cancel their own requests.
913 *
914 * @param cr ContentResolver
915 * @param origId original image id
916 * @param groupId the same groupId used in getThumbnail.
917 */
918 public static void cancelThumbnailRequest(ContentResolver cr, long origId, long groupId) {
919 InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI, groupId);
920 }
921
922 /**
923 * This method checks if the thumbnails of the specified image (origId) has been created.
924 * It will be blocked until the thumbnails are generated.
925 *
926 * @param cr ContentResolver used to dispatch queries to MediaProvider.
927 * @param origId Original image id associated with thumbnail of interest.
928 * @param groupId the id of group to which this request belongs
929 * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND.
930 * @param options this is only used for MINI_KIND when decoding the Bitmap
931 * @return A Bitmap instance. It could be null if the original image
932 * associated with origId doesn't exist or memory is not enough.
933 */
934 public static Bitmap getThumbnail(ContentResolver cr, long origId, long groupId,
935 int kind, BitmapFactory.Options options) {
936 return InternalThumbnails.getThumbnail(cr, origId, groupId, kind, options,
Ray Chen00c575a2009-08-28 14:12:15 -0700937 EXTERNAL_CONTENT_URI, false);
938 }
939
940 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 * Get the content:// style URI for the image media table on the
942 * given volume.
943 *
944 * @param volumeName the name of the volume to get the URI for
945 * @return the URI to the image media table on the given volume
946 */
947 public static Uri getContentUri(String volumeName) {
948 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
949 "/images/thumbnails");
950 }
951
952 /**
953 * The content:// style URI for the internal storage.
954 */
955 public static final Uri INTERNAL_CONTENT_URI =
956 getContentUri("internal");
957
958 /**
959 * The content:// style URI for the "primary" external storage
960 * volume.
961 */
962 public static final Uri EXTERNAL_CONTENT_URI =
963 getContentUri("external");
964
965 /**
966 * The default sort order for this table
967 */
968 public static final String DEFAULT_SORT_ORDER = "image_id ASC";
969
970 /**
971 * The data stream for the thumbnail
972 * <P>Type: DATA STREAM</P>
973 */
974 public static final String DATA = "_data";
975
976 /**
977 * The original image for the thumbnal
978 * <P>Type: INTEGER (ID from Images table)</P>
979 */
980 public static final String IMAGE_ID = "image_id";
981
982 /**
983 * The kind of the thumbnail
984 * <P>Type: INTEGER (One of the values below)</P>
985 */
986 public static final String KIND = "kind";
987
988 public static final int MINI_KIND = 1;
989 public static final int FULL_SCREEN_KIND = 2;
990 public static final int MICRO_KIND = 3;
Ray Chen00c575a2009-08-28 14:12:15 -0700991 /**
992 * The blob raw data of thumbnail
993 * <P>Type: DATA STREAM</P>
994 */
995 public static final String THUMB_DATA = "thumb_data";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996
997 /**
998 * The width of the thumbnal
999 * <P>Type: INTEGER (long)</P>
1000 */
1001 public static final String WIDTH = "width";
1002
1003 /**
1004 * The height of the thumbnail
1005 * <P>Type: INTEGER (long)</P>
1006 */
1007 public static final String HEIGHT = "height";
1008 }
1009 }
1010
1011 /**
1012 * Container for all audio content.
1013 */
1014 public static final class Audio {
1015 /**
1016 * Columns for audio file that show up in multiple tables.
1017 */
1018 public interface AudioColumns extends MediaColumns {
1019
1020 /**
1021 * A non human readable key calculated from the TITLE, used for
1022 * searching, sorting and grouping
1023 * <P>Type: TEXT</P>
1024 */
1025 public static final String TITLE_KEY = "title_key";
1026
1027 /**
1028 * The duration of the audio file, in ms
1029 * <P>Type: INTEGER (long)</P>
1030 */
1031 public static final String DURATION = "duration";
1032
1033 /**
1034 * The position, in ms, playback was at when playback for this file
1035 * was last stopped.
1036 * <P>Type: INTEGER (long)</P>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 */
1038 public static final String BOOKMARK = "bookmark";
1039
1040 /**
1041 * The id of the artist who created the audio file, if any
1042 * <P>Type: INTEGER (long)</P>
1043 */
1044 public static final String ARTIST_ID = "artist_id";
1045
1046 /**
1047 * The artist who created the audio file, if any
1048 * <P>Type: TEXT</P>
1049 */
1050 public static final String ARTIST = "artist";
1051
1052 /**
Marco Nelissenabc28192010-03-18 17:10:38 -07001053 * The artist credited for the album that contains the audio file
1054 * <P>Type: TEXT</P>
1055 * @hide
1056 */
1057 public static final String ALBUM_ARTIST = "album_artist";
1058
1059 /**
Marco Nelissenee35aff2011-01-06 11:12:17 -08001060 * Whether the song is part of a compilation
1061 * <P>Type: TEXT</P>
1062 * @hide
1063 */
1064 public static final String COMPILATION = "compilation";
1065
1066 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 * A non human readable key calculated from the ARTIST, used for
1068 * searching, sorting and grouping
1069 * <P>Type: TEXT</P>
1070 */
1071 public static final String ARTIST_KEY = "artist_key";
1072
1073 /**
1074 * The composer of the audio file, if any
1075 * <P>Type: TEXT</P>
1076 */
1077 public static final String COMPOSER = "composer";
1078
1079 /**
1080 * The id of the album the audio file is from, if any
1081 * <P>Type: INTEGER (long)</P>
1082 */
1083 public static final String ALBUM_ID = "album_id";
1084
1085 /**
1086 * The album the audio file is from, if any
1087 * <P>Type: TEXT</P>
1088 */
1089 public static final String ALBUM = "album";
1090
1091 /**
1092 * A non human readable key calculated from the ALBUM, used for
1093 * searching, sorting and grouping
1094 * <P>Type: TEXT</P>
1095 */
1096 public static final String ALBUM_KEY = "album_key";
1097
1098 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001099 * The track number of this song on the album, if any.
1100 * This number encodes both the track number and the
1101 * disc number. For multi-disc sets, this number will
1102 * be 1xxx for tracks on the first disc, 2xxx for tracks
1103 * on the second disc, etc.
1104 * <P>Type: INTEGER</P>
1105 */
1106 public static final String TRACK = "track";
1107
1108 /**
1109 * The year the audio file was recorded, if any
1110 * <P>Type: INTEGER</P>
1111 */
1112 public static final String YEAR = "year";
1113
1114 /**
1115 * Non-zero if the audio file is music
1116 * <P>Type: INTEGER (boolean)</P>
1117 */
1118 public static final String IS_MUSIC = "is_music";
1119
1120 /**
1121 * Non-zero if the audio file is a podcast
1122 * <P>Type: INTEGER (boolean)</P>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 */
1124 public static final String IS_PODCAST = "is_podcast";
1125
1126 /**
1127 * Non-zero id the audio file may be a ringtone
1128 * <P>Type: INTEGER (boolean)</P>
1129 */
1130 public static final String IS_RINGTONE = "is_ringtone";
1131
1132 /**
1133 * Non-zero id the audio file may be an alarm
1134 * <P>Type: INTEGER (boolean)</P>
1135 */
1136 public static final String IS_ALARM = "is_alarm";
1137
1138 /**
1139 * Non-zero id the audio file may be a notification sound
1140 * <P>Type: INTEGER (boolean)</P>
1141 */
1142 public static final String IS_NOTIFICATION = "is_notification";
1143 }
1144
1145 /**
1146 * Converts a name to a "key" that can be used for grouping, sorting
1147 * and searching.
1148 * The rules that govern this conversion are:
1149 * - remove 'special' characters like ()[]'!?.,
1150 * - remove leading/trailing spaces
1151 * - convert everything to lowercase
1152 * - remove leading "the ", "an " and "a "
1153 * - remove trailing ", the|an|a"
1154 * - remove accents. This step leaves us with CollationKey data,
1155 * which is not human readable
1156 *
1157 * @param name The artist or album name to convert
1158 * @return The "key" for the given name.
1159 */
1160 public static String keyFor(String name) {
1161 if (name != null) {
Marco Nelissen816cf522009-07-06 09:19:10 -07001162 boolean sortfirst = false;
Marco Nelissen9a488b42010-01-04 15:09:03 -08001163 if (name.equals(UNKNOWN_STRING)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 return "\001";
1165 }
Marco Nelissen816cf522009-07-06 09:19:10 -07001166 // Check if the first character is \001. We use this to
1167 // force sorting of certain special files, like the silent ringtone.
1168 if (name.startsWith("\001")) {
1169 sortfirst = true;
1170 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 name = name.trim().toLowerCase();
1172 if (name.startsWith("the ")) {
1173 name = name.substring(4);
1174 }
1175 if (name.startsWith("an ")) {
1176 name = name.substring(3);
1177 }
1178 if (name.startsWith("a ")) {
1179 name = name.substring(2);
1180 }
1181 if (name.endsWith(", the") || name.endsWith(",the") ||
1182 name.endsWith(", an") || name.endsWith(",an") ||
1183 name.endsWith(", a") || name.endsWith(",a")) {
1184 name = name.substring(0, name.lastIndexOf(','));
1185 }
Marco Nelissene754e122009-05-22 12:16:58 -07001186 name = name.replaceAll("[\\[\\]\\(\\)\"'.,?!]", "").trim();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 if (name.length() > 0) {
1188 // Insert a separator between the characters to avoid
1189 // matches on a partial character. If we ever change
1190 // to start-of-word-only matches, this can be removed.
1191 StringBuilder b = new StringBuilder();
1192 b.append('.');
1193 int nl = name.length();
1194 for (int i = 0; i < nl; i++) {
1195 b.append(name.charAt(i));
1196 b.append('.');
1197 }
1198 name = b.toString();
Marco Nelissen816cf522009-07-06 09:19:10 -07001199 String key = DatabaseUtils.getCollationKey(name);
1200 if (sortfirst) {
1201 key = "\001" + key;
1202 }
1203 return key;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 } else {
1205 return "";
1206 }
1207 }
1208 return null;
1209 }
1210
1211 public static final class Media implements AudioColumns {
1212 /**
1213 * Get the content:// style URI for the audio media table on the
1214 * given volume.
1215 *
1216 * @param volumeName the name of the volume to get the URI for
1217 * @return the URI to the audio media table on the given volume
1218 */
1219 public static Uri getContentUri(String volumeName) {
1220 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1221 "/audio/media");
1222 }
1223
1224 public static Uri getContentUriForPath(String path) {
1225 return (path.startsWith(Environment.getExternalStorageDirectory().getPath()) ?
1226 EXTERNAL_CONTENT_URI : INTERNAL_CONTENT_URI);
1227 }
1228
1229 /**
1230 * The content:// style URI for the internal storage.
1231 */
1232 public static final Uri INTERNAL_CONTENT_URI =
1233 getContentUri("internal");
1234
1235 /**
1236 * The content:// style URI for the "primary" external storage
1237 * volume.
1238 */
1239 public static final Uri EXTERNAL_CONTENT_URI =
1240 getContentUri("external");
1241
1242 /**
1243 * The MIME type for this table.
1244 */
1245 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
1246
1247 /**
1248 * The default sort order for this table
1249 */
Marco Nelissen816cf522009-07-06 09:19:10 -07001250 public static final String DEFAULT_SORT_ORDER = TITLE_KEY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251
1252 /**
1253 * Activity Action: Start SoundRecorder application.
1254 * <p>Input: nothing.
1255 * <p>Output: An uri to the recorded sound stored in the Media Library
1256 * if the recording was successful.
1257 * May also contain the extra EXTRA_MAX_BYTES.
1258 * @see #EXTRA_MAX_BYTES
1259 */
1260 public static final String RECORD_SOUND_ACTION =
1261 "android.provider.MediaStore.RECORD_SOUND";
1262
1263 /**
1264 * The name of the Intent-extra used to define a maximum file size for
1265 * a recording made by the SoundRecorder application.
1266 *
1267 * @see #RECORD_SOUND_ACTION
1268 */
1269 public static final String EXTRA_MAX_BYTES =
1270 "android.provider.MediaStore.extra.MAX_BYTES";
1271 }
1272
1273 /**
1274 * Columns representing an audio genre
1275 */
1276 public interface GenresColumns {
1277 /**
1278 * The name of the genre
1279 * <P>Type: TEXT</P>
1280 */
1281 public static final String NAME = "name";
1282 }
1283
1284 /**
1285 * Contains all genres for audio files
1286 */
1287 public static final class Genres implements BaseColumns, GenresColumns {
1288 /**
1289 * Get the content:// style URI for the audio genres table on the
1290 * given volume.
1291 *
1292 * @param volumeName the name of the volume to get the URI for
1293 * @return the URI to the audio genres table on the given volume
1294 */
1295 public static Uri getContentUri(String volumeName) {
1296 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1297 "/audio/genres");
1298 }
1299
1300 /**
Mike Lockwoodbdb05df2010-09-26 12:33:25 -04001301 * Get the content:// style URI for querying the genres of an audio file.
1302 *
1303 * @param volumeName the name of the volume to get the URI for
1304 * @param audioId the ID of the audio file for which to retrieve the genres
1305 * @return the URI to for querying the genres for the audio file
1306 * with the given the volume and audioID
1307 */
1308 public static Uri getContentUriForAudioId(String volumeName, int audioId) {
1309 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1310 "/audio/media/" + audioId + "/genres");
1311 }
1312
1313 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 * The content:// style URI for the internal storage.
1315 */
1316 public static final Uri INTERNAL_CONTENT_URI =
1317 getContentUri("internal");
1318
1319 /**
1320 * The content:// style URI for the "primary" external storage
1321 * volume.
1322 */
1323 public static final Uri EXTERNAL_CONTENT_URI =
1324 getContentUri("external");
1325
1326 /**
1327 * The MIME type for this table.
1328 */
1329 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/genre";
1330
1331 /**
1332 * The MIME type for entries in this table.
1333 */
1334 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/genre";
1335
1336 /**
1337 * The default sort order for this table
1338 */
1339 public static final String DEFAULT_SORT_ORDER = NAME;
1340
1341 /**
1342 * Sub-directory of each genre containing all members.
1343 */
1344 public static final class Members implements AudioColumns {
1345
1346 public static final Uri getContentUri(String volumeName,
1347 long genreId) {
1348 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
1349 + "/audio/genres/" + genreId + "/members");
1350 }
1351
1352 /**
1353 * A subdirectory of each genre containing all member audio files.
1354 */
1355 public static final String CONTENT_DIRECTORY = "members";
1356
1357 /**
1358 * The default sort order for this table
1359 */
Marco Nelissen816cf522009-07-06 09:19:10 -07001360 public static final String DEFAULT_SORT_ORDER = TITLE_KEY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361
1362 /**
1363 * The ID of the audio file
1364 * <P>Type: INTEGER (long)</P>
1365 */
1366 public static final String AUDIO_ID = "audio_id";
1367
1368 /**
1369 * The ID of the genre
1370 * <P>Type: INTEGER (long)</P>
1371 */
1372 public static final String GENRE_ID = "genre_id";
1373 }
1374 }
1375
1376 /**
1377 * Columns representing a playlist
1378 */
1379 public interface PlaylistsColumns {
1380 /**
1381 * The name of the playlist
1382 * <P>Type: TEXT</P>
1383 */
1384 public static final String NAME = "name";
1385
1386 /**
1387 * The data stream for the playlist file
1388 * <P>Type: DATA STREAM</P>
1389 */
1390 public static final String DATA = "_data";
1391
1392 /**
1393 * The time the file was added to the media provider
1394 * Units are seconds since 1970.
1395 * <P>Type: INTEGER (long)</P>
1396 */
1397 public static final String DATE_ADDED = "date_added";
1398
1399 /**
1400 * The time the file was last modified
1401 * Units are seconds since 1970.
1402 * NOTE: This is for internal use by the media scanner. Do not modify this field.
1403 * <P>Type: INTEGER (long)</P>
1404 */
1405 public static final String DATE_MODIFIED = "date_modified";
1406 }
1407
1408 /**
1409 * Contains playlists for audio files
1410 */
1411 public static final class Playlists implements BaseColumns,
1412 PlaylistsColumns {
1413 /**
1414 * Get the content:// style URI for the audio playlists table on the
1415 * given volume.
1416 *
1417 * @param volumeName the name of the volume to get the URI for
1418 * @return the URI to the audio playlists table on the given volume
1419 */
1420 public static Uri getContentUri(String volumeName) {
1421 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1422 "/audio/playlists");
1423 }
1424
1425 /**
1426 * The content:// style URI for the internal storage.
1427 */
1428 public static final Uri INTERNAL_CONTENT_URI =
1429 getContentUri("internal");
1430
1431 /**
1432 * The content:// style URI for the "primary" external storage
1433 * volume.
1434 */
1435 public static final Uri EXTERNAL_CONTENT_URI =
1436 getContentUri("external");
1437
1438 /**
1439 * The MIME type for this table.
1440 */
1441 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/playlist";
1442
1443 /**
1444 * The MIME type for entries in this table.
1445 */
1446 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/playlist";
1447
1448 /**
1449 * The default sort order for this table
1450 */
1451 public static final String DEFAULT_SORT_ORDER = NAME;
1452
1453 /**
1454 * Sub-directory of each playlist containing all members.
1455 */
1456 public static final class Members implements AudioColumns {
1457 public static final Uri getContentUri(String volumeName,
1458 long playlistId) {
1459 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
1460 + "/audio/playlists/" + playlistId + "/members");
1461 }
1462
1463 /**
Marco Nelissene3d05fc2009-12-09 16:01:46 -08001464 * Convenience method to move a playlist item to a new location
1465 * @param res The content resolver to use
1466 * @param playlistId The numeric id of the playlist
1467 * @param from The position of the item to move
1468 * @param to The position to move the item to
1469 * @return true on success
Marco Nelissene3d05fc2009-12-09 16:01:46 -08001470 */
1471 public static final boolean moveItem(ContentResolver res,
1472 long playlistId, int from, int to) {
1473 Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external",
1474 playlistId)
1475 .buildUpon()
1476 .appendEncodedPath(String.valueOf(from))
1477 .appendQueryParameter("move", "true")
1478 .build();
1479 ContentValues values = new ContentValues();
1480 values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, to);
1481 return res.update(uri, values, null, null) != 0;
1482 }
1483
1484 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 * The ID within the playlist.
1486 */
1487 public static final String _ID = "_id";
1488
1489 /**
1490 * A subdirectory of each playlist containing all member audio
1491 * files.
1492 */
1493 public static final String CONTENT_DIRECTORY = "members";
1494
1495 /**
1496 * The ID of the audio file
1497 * <P>Type: INTEGER (long)</P>
1498 */
1499 public static final String AUDIO_ID = "audio_id";
1500
1501 /**
1502 * The ID of the playlist
1503 * <P>Type: INTEGER (long)</P>
1504 */
1505 public static final String PLAYLIST_ID = "playlist_id";
1506
1507 /**
1508 * The order of the songs in the playlist
1509 * <P>Type: INTEGER (long)></P>
1510 */
1511 public static final String PLAY_ORDER = "play_order";
1512
1513 /**
1514 * The default sort order for this table
1515 */
1516 public static final String DEFAULT_SORT_ORDER = PLAY_ORDER;
1517 }
1518 }
1519
1520 /**
1521 * Columns representing an artist
1522 */
1523 public interface ArtistColumns {
1524 /**
1525 * The artist who created the audio file, if any
1526 * <P>Type: TEXT</P>
1527 */
1528 public static final String ARTIST = "artist";
1529
1530 /**
1531 * A non human readable key calculated from the ARTIST, used for
1532 * searching, sorting and grouping
1533 * <P>Type: TEXT</P>
1534 */
1535 public static final String ARTIST_KEY = "artist_key";
1536
1537 /**
1538 * The number of albums in the database for this artist
1539 */
1540 public static final String NUMBER_OF_ALBUMS = "number_of_albums";
1541
1542 /**
1543 * The number of albums in the database for this artist
1544 */
1545 public static final String NUMBER_OF_TRACKS = "number_of_tracks";
1546 }
1547
1548 /**
1549 * Contains artists for audio files
1550 */
1551 public static final class Artists implements BaseColumns, ArtistColumns {
1552 /**
1553 * Get the content:// style URI for the artists table on the
1554 * given volume.
1555 *
1556 * @param volumeName the name of the volume to get the URI for
1557 * @return the URI to the audio artists table on the given volume
1558 */
1559 public static Uri getContentUri(String volumeName) {
1560 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1561 "/audio/artists");
1562 }
1563
1564 /**
1565 * The content:// style URI for the internal storage.
1566 */
1567 public static final Uri INTERNAL_CONTENT_URI =
1568 getContentUri("internal");
1569
1570 /**
1571 * The content:// style URI for the "primary" external storage
1572 * volume.
1573 */
1574 public static final Uri EXTERNAL_CONTENT_URI =
1575 getContentUri("external");
1576
1577 /**
1578 * The MIME type for this table.
1579 */
1580 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/artists";
1581
1582 /**
1583 * The MIME type for entries in this table.
1584 */
1585 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/artist";
1586
1587 /**
1588 * The default sort order for this table
1589 */
1590 public static final String DEFAULT_SORT_ORDER = ARTIST_KEY;
1591
1592 /**
1593 * Sub-directory of each artist containing all albums on which
1594 * a song by the artist appears.
1595 */
1596 public static final class Albums implements AlbumColumns {
1597 public static final Uri getContentUri(String volumeName,
1598 long artistId) {
1599 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
1600 + "/audio/artists/" + artistId + "/albums");
1601 }
1602 }
1603 }
1604
1605 /**
1606 * Columns representing an album
1607 */
1608 public interface AlbumColumns {
1609
1610 /**
1611 * The id for the album
1612 * <P>Type: INTEGER</P>
1613 */
1614 public static final String ALBUM_ID = "album_id";
1615
1616 /**
1617 * The album on which the audio file appears, if any
1618 * <P>Type: TEXT</P>
1619 */
1620 public static final String ALBUM = "album";
1621
1622 /**
1623 * The artist whose songs appear on this album
1624 * <P>Type: TEXT</P>
1625 */
1626 public static final String ARTIST = "artist";
1627
1628 /**
1629 * The number of songs on this album
1630 * <P>Type: INTEGER</P>
1631 */
1632 public static final String NUMBER_OF_SONGS = "numsongs";
1633
1634 /**
1635 * This column is available when getting album info via artist,
1636 * and indicates the number of songs on the album by the given
1637 * artist.
1638 * <P>Type: INTEGER</P>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 */
1640 public static final String NUMBER_OF_SONGS_FOR_ARTIST = "numsongs_by_artist";
1641
1642 /**
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07001643 * The year in which the earliest songs
1644 * on this album were released. This will often
1645 * be the same as {@link #LAST_YEAR}, but for compilation albums
1646 * they might differ.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 * <P>Type: INTEGER</P>
1648 */
1649 public static final String FIRST_YEAR = "minyear";
Ray Chen00c575a2009-08-28 14:12:15 -07001650
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07001651 /**
1652 * The year in which the latest songs
1653 * on this album were released. This will often
1654 * be the same as {@link #FIRST_YEAR}, but for compilation albums
1655 * they might differ.
1656 * <P>Type: INTEGER</P>
1657 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 public static final String LAST_YEAR = "maxyear";
1659
1660 /**
1661 * A non human readable key calculated from the ALBUM, used for
1662 * searching, sorting and grouping
1663 * <P>Type: TEXT</P>
1664 */
1665 public static final String ALBUM_KEY = "album_key";
1666
1667 /**
1668 * Cached album art.
1669 * <P>Type: TEXT</P>
1670 */
1671 public static final String ALBUM_ART = "album_art";
1672 }
1673
1674 /**
1675 * Contains artists for audio files
1676 */
1677 public static final class Albums implements BaseColumns, AlbumColumns {
1678 /**
1679 * Get the content:// style URI for the albums table on the
1680 * given volume.
1681 *
1682 * @param volumeName the name of the volume to get the URI for
1683 * @return the URI to the audio albums table on the given volume
1684 */
1685 public static Uri getContentUri(String volumeName) {
1686 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1687 "/audio/albums");
1688 }
1689
1690 /**
1691 * The content:// style URI for the internal storage.
1692 */
1693 public static final Uri INTERNAL_CONTENT_URI =
1694 getContentUri("internal");
1695
1696 /**
1697 * The content:// style URI for the "primary" external storage
1698 * volume.
1699 */
1700 public static final Uri EXTERNAL_CONTENT_URI =
1701 getContentUri("external");
1702
1703 /**
1704 * The MIME type for this table.
1705 */
1706 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/albums";
1707
1708 /**
1709 * The MIME type for entries in this table.
1710 */
1711 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/album";
1712
1713 /**
1714 * The default sort order for this table
1715 */
1716 public static final String DEFAULT_SORT_ORDER = ALBUM_KEY;
1717 }
1718 }
1719
1720 public static final class Video {
1721
1722 /**
1723 * The default sort order for this table.
1724 */
1725 public static final String DEFAULT_SORT_ORDER = MediaColumns.DISPLAY_NAME;
1726
Ray Chen00c575a2009-08-28 14:12:15 -07001727 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
1729 }
1730
1731 public interface VideoColumns extends MediaColumns {
1732
1733 /**
1734 * The duration of the video file, in ms
1735 * <P>Type: INTEGER (long)</P>
1736 */
1737 public static final String DURATION = "duration";
1738
1739 /**
1740 * The artist who created the video file, if any
1741 * <P>Type: TEXT</P>
1742 */
1743 public static final String ARTIST = "artist";
1744
1745 /**
1746 * The album the video file is from, if any
1747 * <P>Type: TEXT</P>
1748 */
1749 public static final String ALBUM = "album";
1750
1751 /**
1752 * The resolution of the video file, formatted as "XxY"
1753 * <P>Type: TEXT</P>
1754 */
1755 public static final String RESOLUTION = "resolution";
1756
1757 /**
1758 * The description of the video recording
1759 * <P>Type: TEXT</P>
1760 */
1761 public static final String DESCRIPTION = "description";
1762
1763 /**
1764 * Whether the video should be published as public or private
1765 * <P>Type: INTEGER</P>
1766 */
1767 public static final String IS_PRIVATE = "isprivate";
1768
1769 /**
1770 * The user-added tags associated with a video
1771 * <P>Type: TEXT</P>
1772 */
1773 public static final String TAGS = "tags";
1774
1775 /**
1776 * The YouTube category of the video
1777 * <P>Type: TEXT</P>
1778 */
1779 public static final String CATEGORY = "category";
1780
1781 /**
1782 * The language of the video
1783 * <P>Type: TEXT</P>
1784 */
1785 public static final String LANGUAGE = "language";
1786
1787 /**
1788 * The latitude where the image was captured.
1789 * <P>Type: DOUBLE</P>
1790 */
1791 public static final String LATITUDE = "latitude";
1792
1793 /**
1794 * The longitude where the image was captured.
1795 * <P>Type: DOUBLE</P>
1796 */
1797 public static final String LONGITUDE = "longitude";
1798
1799 /**
1800 * The date & time that the image was taken in units
1801 * of milliseconds since jan 1, 1970.
1802 * <P>Type: INTEGER</P>
1803 */
1804 public static final String DATE_TAKEN = "datetaken";
1805
1806 /**
1807 * The mini thumb id.
1808 * <P>Type: INTEGER</P>
1809 */
1810 public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
1811
1812 /**
1813 * The bucket id of the video. This is a read-only property that
1814 * is automatically computed from the DATA column.
1815 * <P>Type: TEXT</P>
1816 */
1817 public static final String BUCKET_ID = "bucket_id";
1818
1819 /**
1820 * The bucket display name of the video. This is a read-only property that
1821 * is automatically computed from the DATA column.
1822 * <P>Type: TEXT</P>
1823 */
1824 public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
1825
1826 /**
1827 * The bookmark for the video. Time in ms. Represents the location in the video that the
1828 * video should start playing at the next time it is opened. If the value is null or
1829 * out of the range 0..DURATION-1 then the video should start playing from the
1830 * beginning.
1831 * <P>Type: INTEGER</P>
1832 */
1833 public static final String BOOKMARK = "bookmark";
1834 }
1835
1836 public static final class Media implements VideoColumns {
1837 /**
1838 * Get the content:// style URI for the video media table on the
1839 * given volume.
1840 *
1841 * @param volumeName the name of the volume to get the URI for
1842 * @return the URI to the video media table on the given volume
1843 */
1844 public static Uri getContentUri(String volumeName) {
1845 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1846 "/video/media");
1847 }
1848
1849 /**
1850 * The content:// style URI for the internal storage.
1851 */
1852 public static final Uri INTERNAL_CONTENT_URI =
1853 getContentUri("internal");
1854
1855 /**
1856 * The content:// style URI for the "primary" external storage
1857 * volume.
1858 */
1859 public static final Uri EXTERNAL_CONTENT_URI =
1860 getContentUri("external");
1861
1862 /**
1863 * The MIME type for this table.
1864 */
1865 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/video";
1866
1867 /**
1868 * The default sort order for this table
1869 */
1870 public static final String DEFAULT_SORT_ORDER = TITLE;
1871 }
Ray Chen00c575a2009-08-28 14:12:15 -07001872
1873 /**
1874 * This class allows developers to query and get two kinds of thumbnails:
1875 * MINI_KIND: 512 x 384 thumbnail
1876 * MICRO_KIND: 96 x 96 thumbnail
1877 *
1878 */
1879 public static class Thumbnails implements BaseColumns {
1880 /**
Ray Chenb9944192009-09-29 20:24:01 -07001881 * This method cancels the thumbnail request so clients waiting for getThumbnail will be
1882 * interrupted and return immediately. Only the original process which made the getThumbnail
1883 * requests can cancel their own requests.
1884 *
1885 * @param cr ContentResolver
1886 * @param origId original video id
1887 */
1888 public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
Ray Chen13ed5752009-10-05 12:21:24 -07001889 InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI,
1890 InternalThumbnails.DEFAULT_GROUP_ID);
Ray Chenb9944192009-09-29 20:24:01 -07001891 }
1892
1893 /**
Ray Chen00c575a2009-08-28 14:12:15 -07001894 * This method checks if the thumbnails of the specified image (origId) has been created.
1895 * It will be blocked until the thumbnails are generated.
1896 *
1897 * @param cr ContentResolver used to dispatch queries to MediaProvider.
1898 * @param origId Original image id associated with thumbnail of interest.
Ray Chen13ed5752009-10-05 12:21:24 -07001899 * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND.
1900 * @param options this is only used for MINI_KIND when decoding the Bitmap
1901 * @return A Bitmap instance. It could be null if the original image
1902 * associated with origId doesn't exist or memory is not enough.
1903 */
1904 public static Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
1905 BitmapFactory.Options options) {
1906 return InternalThumbnails.getThumbnail(cr, origId,
1907 InternalThumbnails.DEFAULT_GROUP_ID, kind, options,
1908 EXTERNAL_CONTENT_URI, true);
1909 }
1910
1911 /**
1912 * This method checks if the thumbnails of the specified image (origId) has been created.
1913 * It will be blocked until the thumbnails are generated.
1914 *
1915 * @param cr ContentResolver used to dispatch queries to MediaProvider.
1916 * @param origId Original image id associated with thumbnail of interest.
1917 * @param groupId the id of group to which this request belongs
Ray Chen00c575a2009-08-28 14:12:15 -07001918 * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND
1919 * @param options this is only used for MINI_KIND when decoding the Bitmap
1920 * @return A Bitmap instance. It could be null if the original image associated with
1921 * origId doesn't exist or memory is not enough.
1922 */
Ray Chen13ed5752009-10-05 12:21:24 -07001923 public static Bitmap getThumbnail(ContentResolver cr, long origId, long groupId,
1924 int kind, BitmapFactory.Options options) {
1925 return InternalThumbnails.getThumbnail(cr, origId, groupId, kind, options,
Ray Chen00c575a2009-08-28 14:12:15 -07001926 EXTERNAL_CONTENT_URI, true);
1927 }
1928
1929 /**
Ray Chen13ed5752009-10-05 12:21:24 -07001930 * This method cancels the thumbnail request so clients waiting for getThumbnail will be
1931 * interrupted and return immediately. Only the original process which made the getThumbnail
1932 * requests can cancel their own requests.
1933 *
1934 * @param cr ContentResolver
1935 * @param origId original video id
1936 * @param groupId the same groupId used in getThumbnail.
1937 */
1938 public static void cancelThumbnailRequest(ContentResolver cr, long origId, long groupId) {
1939 InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI, groupId);
1940 }
1941
1942 /**
Ray Chen00c575a2009-08-28 14:12:15 -07001943 * Get the content:// style URI for the image media table on the
1944 * given volume.
1945 *
1946 * @param volumeName the name of the volume to get the URI for
1947 * @return the URI to the image media table on the given volume
1948 */
1949 public static Uri getContentUri(String volumeName) {
1950 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1951 "/video/thumbnails");
1952 }
1953
1954 /**
1955 * The content:// style URI for the internal storage.
1956 */
1957 public static final Uri INTERNAL_CONTENT_URI =
1958 getContentUri("internal");
1959
1960 /**
1961 * The content:// style URI for the "primary" external storage
1962 * volume.
1963 */
1964 public static final Uri EXTERNAL_CONTENT_URI =
1965 getContentUri("external");
1966
1967 /**
1968 * The default sort order for this table
1969 */
1970 public static final String DEFAULT_SORT_ORDER = "video_id ASC";
1971
1972 /**
1973 * The data stream for the thumbnail
1974 * <P>Type: DATA STREAM</P>
1975 */
1976 public static final String DATA = "_data";
1977
1978 /**
1979 * The original image for the thumbnal
1980 * <P>Type: INTEGER (ID from Video table)</P>
1981 */
1982 public static final String VIDEO_ID = "video_id";
1983
1984 /**
1985 * The kind of the thumbnail
1986 * <P>Type: INTEGER (One of the values below)</P>
1987 */
1988 public static final String KIND = "kind";
1989
1990 public static final int MINI_KIND = 1;
1991 public static final int FULL_SCREEN_KIND = 2;
1992 public static final int MICRO_KIND = 3;
1993
1994 /**
1995 * The width of the thumbnal
1996 * <P>Type: INTEGER (long)</P>
1997 */
1998 public static final String WIDTH = "width";
1999
2000 /**
2001 * The height of the thumbnail
2002 * <P>Type: INTEGER (long)</P>
2003 */
2004 public static final String HEIGHT = "height";
2005 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002006 }
2007
2008 /**
2009 * Uri for querying the state of the media scanner.
2010 */
2011 public static Uri getMediaScannerUri() {
2012 return Uri.parse(CONTENT_AUTHORITY_SLASH + "none/media_scanner");
2013 }
2014
2015 /**
2016 * Name of current volume being scanned by the media scanner.
2017 */
2018 public static final String MEDIA_SCANNER_VOLUME = "volume";
Karl Ostmo8ce072d2010-01-30 15:15:39 -06002019
2020 /**
2021 * Name of the file signaling the media scanner to ignore media in the containing directory
2022 * and its subdirectories. Developers should use this to avoid application graphics showing
2023 * up in the Gallery and likewise prevent application sounds and music from showing up in
2024 * the Music app.
2025 */
2026 public static final String MEDIA_IGNORE_FILENAME = ".nomedia";
Marco Nelissen3822f732011-02-03 10:59:30 -08002027
2028 /**
2029 * Get the media provider's version.
2030 * Applications that import data from the media provider into their own caches
2031 * can use this to detect that the media provider changed, and reimport data
2032 * as needed. No other assumptions should be made about the meaning of the version.
2033 * @param context Context to use for performing the query.
2034 * @return A version string, or null if the version could not be determined.
Marco Nelissen3822f732011-02-03 10:59:30 -08002035 */
2036 public static String getVersion(Context context) {
2037 Cursor c = context.getContentResolver().query(
2038 Uri.parse(CONTENT_AUTHORITY_SLASH + "none/version"),
2039 null, null, null, null);
2040 if (c != null) {
2041 try {
2042 if (c.moveToFirst()) {
2043 return c.getString(0);
2044 }
2045 } finally {
2046 c.close();
2047 }
2048 }
2049 return null;
2050 }
2051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052}