blob: c9b2f973aacadb950019b7ddf287620aac80fa0d [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
169 * @see #EXTRA_VIDEO_QUALITY
170 */
171 public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
172
173 /**
174 * Standard Intent action that can be sent to have the camera application
175 * capture an video and return it.
176 * <p>
177 * The caller may pass in an extra EXTRA_VIDEO_QUALITY to control the video quality.
178 * <p>
179 * The caller may pass in an extra EXTRA_OUTPUT to control
180 * where the video is written. If EXTRA_OUTPUT is not present the video will be
181 * written to the standard location for videos, and the Uri of that location will be
182 * returned in the data field of the Uri.
183 * @see #EXTRA_OUTPUT
184 */
185 public final static String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
186
187 /**
188 * The name of the Intent-extra used to control the quality of a recorded video. This is an
189 * integer property. Currently value 0 means low quality, suitable for MMS messages, and
190 * value 1 means high quality. In the future other quality levels may be added.
191 */
192 public final static String EXTRA_VIDEO_QUALITY = "android.intent.extra.videoQuality";
193
194 /**
195 * Specify the maximum allowed size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 */
197 public final static String EXTRA_SIZE_LIMIT = "android.intent.extra.sizeLimit";
198
199 /**
Chih-Chung Changeb0098d2009-08-25 12:59:54 +0800200 * Specify the maximum allowed recording duration in seconds.
Chih-Chung Changeb0098d2009-08-25 12:59:54 +0800201 */
202 public final static String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
203
204 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 * The name of the Intent-extra used to indicate a content resolver Uri to be used to
206 * store the requested image or video.
207 */
208 public final static String EXTRA_OUTPUT = "output";
209
210 /**
Marco Nelissened297a82010-01-04 13:24:31 -0800211 * The string that is used when a media attribute is not known. For example,
212 * if an audio file does not have any meta data, the artist and album columns
213 * will be set to this value.
Marco Nelissened297a82010-01-04 13:24:31 -0800214 */
215 public static final String UNKNOWN_STRING = "<unknown>";
216
217 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 * Common fields for most MediaProvider tables
219 */
220
Ray Chen00c575a2009-08-28 14:12:15 -0700221 public interface MediaColumns extends BaseColumns {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 /**
223 * The data stream for the file
224 * <P>Type: DATA STREAM</P>
225 */
226 public static final String DATA = "_data";
227
228 /**
229 * The size of the file in bytes
230 * <P>Type: INTEGER (long)</P>
231 */
232 public static final String SIZE = "_size";
233
234 /**
235 * The display name of the file
236 * <P>Type: TEXT</P>
237 */
238 public static final String DISPLAY_NAME = "_display_name";
239
240 /**
241 * The title of the content
242 * <P>Type: TEXT</P>
243 */
244 public static final String TITLE = "title";
245
246 /**
247 * The time the file was added to the media provider
248 * Units are seconds since 1970.
249 * <P>Type: INTEGER (long)</P>
250 */
251 public static final String DATE_ADDED = "date_added";
252
253 /**
254 * The time the file was last modified
255 * Units are seconds since 1970.
256 * NOTE: This is for internal use by the media scanner. Do not modify this field.
257 * <P>Type: INTEGER (long)</P>
258 */
259 public static final String DATE_MODIFIED = "date_modified";
260
261 /**
262 * The MIME type of the file
263 * <P>Type: TEXT</P>
264 */
265 public static final String MIME_TYPE = "mime_type";
Mike Lockwoodd815f792010-07-12 08:49:01 -0400266
267 /**
Mike Lockwoodcbaea352010-07-17 08:34:17 -0400268 * The MTP object handle of a newly transfered file.
269 * Used to pass the new file's object handle through the media scanner
270 * from MTP to the media provider
271 * For internal use only by MTP, media scanner and media provider.
272 * <P>Type: INTEGER</P>
273 * @hide
274 */
275 public static final String MEDIA_SCANNER_NEW_OBJECT_ID = "media_scanner_new_object_id";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 }
277
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400278 /**
Mike Lockwood0b20b772010-11-04 13:16:48 -0400279 * Media provider table containing an index of all files in the media storage,
280 * including non-media files. This should be used by applications that work with
281 * non-media file types (text, HTML, PDF, etc) as well as applications that need to
282 * work with multiple media file types in a single query.
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400283 */
Mike Lockwood3b2a62e2010-09-08 12:47:57 -0400284 public static final class Files {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400285
Mike Lockwood0b20b772010-11-04 13:16:48 -0400286 /**
287 * Get the content:// style URI for the files table on the
288 * given volume.
289 *
290 * @param volumeName the name of the volume to get the URI for
291 * @return the URI to the files table on the given volume
292 */
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400293 public static Uri getContentUri(String volumeName) {
294 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
Mike Lockwood3b2a62e2010-09-08 12:47:57 -0400295 "/file");
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400296 }
297
Mike Lockwood0b20b772010-11-04 13:16:48 -0400298 /**
299 * Get the content:// style URI for a single row in the files table on the
300 * given volume.
301 *
302 * @param volumeName the name of the volume to get the URI for
303 * @param rowId the file to get the URI for
304 * @return the URI to the files table on the given volume
305 */
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400306 public static final Uri getContentUri(String volumeName,
Mike Lockwood0b20b772010-11-04 13:16:48 -0400307 long rowId) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400308 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
Mike Lockwood0b20b772010-11-04 13:16:48 -0400309 + "/file/" + rowId);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400310 }
311
Mike Lockwood0b20b772010-11-04 13:16:48 -0400312 /**
313 * For use only by the MTP implementation.
314 * @hide
315 */
Mike Lockwood8490e662010-09-09 14:16:22 -0400316 public static Uri getMtpObjectsUri(String volumeName) {
317 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
318 "/object");
319 }
320
Mike Lockwood0b20b772010-11-04 13:16:48 -0400321 /**
322 * For use only by the MTP implementation.
323 * @hide
324 */
Mike Lockwood8490e662010-09-09 14:16:22 -0400325 public static final Uri getMtpObjectsUri(String volumeName,
Mike Lockwood3b2a62e2010-09-08 12:47:57 -0400326 long fileId) {
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400327 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
Mike Lockwood8490e662010-09-09 14:16:22 -0400328 + "/object/" + fileId);
329 }
330
Mike Lockwood0b20b772010-11-04 13:16:48 -0400331 /**
332 * Used to implement the MTP GetObjectReferences and SetObjectReferences commands.
333 * @hide
334 */
Mike Lockwood8490e662010-09-09 14:16:22 -0400335 public static final Uri getMtpReferencesUri(String volumeName,
336 long fileId) {
337 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
338 + "/object/" + fileId + "/references");
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400339 }
340
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400341 /**
342 * Fields for master table for all media files.
343 * Table also contains MediaColumns._ID, DATA, SIZE and DATE_MODIFIED.
344 */
Mike Lockwood3b2a62e2010-09-08 12:47:57 -0400345 public interface FileColumns extends MediaColumns {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400346 /**
Mike Lockwoodd3e4290c2011-04-05 10:21:27 -0400347 * The MTP storage ID of the file
348 * <P>Type: INTEGER</P>
349 * @hide
350 */
351 public static final String STORAGE_ID = "storage_id";
352
353 /**
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400354 * The MTP format code of the file
355 * <P>Type: INTEGER</P>
Mike Lockwood0b20b772010-11-04 13:16:48 -0400356 * @hide
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400357 */
358 public static final String FORMAT = "format";
359
360 /**
361 * The index of the parent directory of the file
362 * <P>Type: INTEGER</P>
363 */
364 public static final String PARENT = "parent";
Mike Lockwoodfed16172010-07-09 10:46:02 -0400365
366 /**
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400367 * The MIME type of the file
368 * <P>Type: TEXT</P>
Mike Lockwoodfed16172010-07-09 10:46:02 -0400369 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400370 public static final String MIME_TYPE = "mime_type";
Mike Lockwoodfed16172010-07-09 10:46:02 -0400371
372 /**
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400373 * The title of the content
374 * <P>Type: TEXT</P>
Mike Lockwoodfed16172010-07-09 10:46:02 -0400375 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400376 public static final String TITLE = "title";
377
378 /**
379 * The media type (audio, video, image or playlist)
380 * of the file, or 0 for not a media file
381 * <P>Type: TEXT</P>
382 */
383 public static final String MEDIA_TYPE = "media_type";
384
385 /**
Mike Lockwooded723b42011-01-26 15:57:07 -0800386 * Constant for the {@link #MEDIA_TYPE} column indicating that file
387 * is not an audio, image, video or playlist file.
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400388 */
389 public static final int MEDIA_TYPE_NONE = 0;
Mike Lockwooded723b42011-01-26 15:57:07 -0800390
391 /**
392 * Constant for the {@link #MEDIA_TYPE} column indicating that file is an image file.
393 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400394 public static final int MEDIA_TYPE_IMAGE = 1;
Mike Lockwooded723b42011-01-26 15:57:07 -0800395
396 /**
397 * Constant for the {@link #MEDIA_TYPE} column indicating that file is an audio file.
398 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400399 public static final int MEDIA_TYPE_AUDIO = 2;
Mike Lockwooded723b42011-01-26 15:57:07 -0800400
401 /**
402 * Constant for the {@link #MEDIA_TYPE} column indicating that file is an video file.
403 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400404 public static final int MEDIA_TYPE_VIDEO = 3;
Mike Lockwooded723b42011-01-26 15:57:07 -0800405
406 /**
407 * Constant for the {@link #MEDIA_TYPE} column indicating that file is an playlist file.
408 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -0400409 public static final int MEDIA_TYPE_PLAYLIST = 4;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400410 }
411 }
412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 /**
Ray Chen00c575a2009-08-28 14:12:15 -0700414 * This class is used internally by Images.Thumbnails and Video.Thumbnails, it's not intended
415 * to be accessed elsewhere.
416 */
417 private static class InternalThumbnails implements BaseColumns {
418 private static final int MINI_KIND = 1;
419 private static final int FULL_SCREEN_KIND = 2;
420 private static final int MICRO_KIND = 3;
421 private static final String[] PROJECTION = new String[] {_ID, MediaColumns.DATA};
Ray Chen13ed5752009-10-05 12:21:24 -0700422 static final int DEFAULT_GROUP_ID = 0;
Chih-Chung Chang2ca36192010-08-24 19:25:56 +0800423 private static final Object sThumbBufLock = new Object();
424 private static byte[] sThumbBuf;
Ray Chen00c575a2009-08-28 14:12:15 -0700425
Ray Chenf9a243d2009-10-29 18:15:29 -0700426 private static Bitmap getMiniThumbFromFile(Cursor c, Uri baseUri, ContentResolver cr, BitmapFactory.Options options) {
427 Bitmap bitmap = null;
428 Uri thumbUri = null;
429 try {
430 long thumbId = c.getLong(0);
431 String filePath = c.getString(1);
432 thumbUri = ContentUris.withAppendedId(baseUri, thumbId);
433 ParcelFileDescriptor pfdInput = cr.openFileDescriptor(thumbUri, "r");
434 bitmap = BitmapFactory.decodeFileDescriptor(
435 pfdInput.getFileDescriptor(), null, options);
436 pfdInput.close();
437 } catch (FileNotFoundException ex) {
438 Log.e(TAG, "couldn't open thumbnail " + thumbUri + "; " + ex);
439 } catch (IOException ex) {
440 Log.e(TAG, "couldn't open thumbnail " + thumbUri + "; " + ex);
441 } catch (OutOfMemoryError ex) {
442 Log.e(TAG, "failed to allocate memory for thumbnail "
443 + thumbUri + "; " + ex);
444 }
445 return bitmap;
446 }
447
Ray Chen00c575a2009-08-28 14:12:15 -0700448 /**
Ray Chenb9944192009-09-29 20:24:01 -0700449 * This method cancels the thumbnail request so clients waiting for getThumbnail will be
450 * interrupted and return immediately. Only the original process which made the getThumbnail
451 * requests can cancel their own requests.
452 *
453 * @param cr ContentResolver
Ray Chenef093cd2009-09-29 19:38:58 -0700454 * @param origId original image or video id. use -1 to cancel all requests.
Ray Chen13ed5752009-10-05 12:21:24 -0700455 * @param groupId the same groupId used in getThumbnail
Ray Chenb9944192009-09-29 20:24:01 -0700456 * @param baseUri the base URI of requested thumbnails
457 */
Ray Chen13ed5752009-10-05 12:21:24 -0700458 static void cancelThumbnailRequest(ContentResolver cr, long origId, Uri baseUri,
459 long groupId) {
Ray Chenb9944192009-09-29 20:24:01 -0700460 Uri cancelUri = baseUri.buildUpon().appendQueryParameter("cancel", "1")
Ray Chen13ed5752009-10-05 12:21:24 -0700461 .appendQueryParameter("orig_id", String.valueOf(origId))
462 .appendQueryParameter("group_id", String.valueOf(groupId)).build();
Ray Chenb9944192009-09-29 20:24:01 -0700463 Cursor c = null;
464 try {
465 c = cr.query(cancelUri, PROJECTION, null, null, null);
466 }
467 finally {
468 if (c != null) c.close();
469 }
470 }
471 /**
Ray Chen00c575a2009-08-28 14:12:15 -0700472 * This method ensure thumbnails associated with origId are generated and decode the byte
473 * stream from database (MICRO_KIND) or file (MINI_KIND).
474 *
475 * Special optimization has been done to avoid further IPC communication for MICRO_KIND
476 * thumbnails.
477 *
478 * @param cr ContentResolver
479 * @param origId original image or video id
480 * @param kind could be MINI_KIND or MICRO_KIND
481 * @param options this is only used for MINI_KIND when decoding the Bitmap
482 * @param baseUri the base URI of requested thumbnails
Ray Chen13ed5752009-10-05 12:21:24 -0700483 * @param groupId the id of group to which this request belongs
Ray Chen00c575a2009-08-28 14:12:15 -0700484 * @return Bitmap bitmap of specified thumbnail kind
485 */
Ray Chen13ed5752009-10-05 12:21:24 -0700486 static Bitmap getThumbnail(ContentResolver cr, long origId, long groupId, int kind,
Ray Chen00c575a2009-08-28 14:12:15 -0700487 BitmapFactory.Options options, Uri baseUri, boolean isVideo) {
488 Bitmap bitmap = null;
489 String filePath = null;
Ray Chenb9944192009-09-29 20:24:01 -0700490 // Log.v(TAG, "getThumbnail: origId="+origId+", kind="+kind+", isVideo="+isVideo);
Ray Chenf9a243d2009-10-29 18:15:29 -0700491 // If the magic is non-zero, we simply return thumbnail if it does exist.
Ray Chen00c575a2009-08-28 14:12:15 -0700492 // querying MediaProvider and simply return thumbnail.
Ray Chen1ba38b62010-05-14 13:50:04 -0700493 MiniThumbFile thumbFile = new MiniThumbFile(isVideo ? Video.Media.EXTERNAL_CONTENT_URI
494 : Images.Media.EXTERNAL_CONTENT_URI);
495 Cursor c = null;
496 try {
497 long magic = thumbFile.getMagic(origId);
498 if (magic != 0) {
499 if (kind == MICRO_KIND) {
Chih-Chung Chang94392412010-08-25 15:54:51 +0800500 synchronized (sThumbBufLock) {
501 if (sThumbBuf == null) {
502 sThumbBuf = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
503 }
504 if (thumbFile.getMiniThumbFromFile(origId, sThumbBuf) != null) {
505 bitmap = BitmapFactory.decodeByteArray(sThumbBuf, 0, sThumbBuf.length);
506 if (bitmap == null) {
507 Log.w(TAG, "couldn't decode byte array.");
508 }
Ray Chen1ba38b62010-05-14 13:50:04 -0700509 }
Ray Chen00c575a2009-08-28 14:12:15 -0700510 }
Ray Chen1ba38b62010-05-14 13:50:04 -0700511 return bitmap;
512 } else if (kind == MINI_KIND) {
513 String column = isVideo ? "video_id=" : "image_id=";
Ray Chenf9a243d2009-10-29 18:15:29 -0700514 c = cr.query(baseUri, PROJECTION, column + origId, null, null);
515 if (c != null && c.moveToFirst()) {
516 bitmap = getMiniThumbFromFile(c, baseUri, cr, options);
517 if (bitmap != null) {
518 return bitmap;
519 }
520 }
Ray Chenf9a243d2009-10-29 18:15:29 -0700521 }
Ray Chen00c575a2009-08-28 14:12:15 -0700522 }
Ray Chen00c575a2009-08-28 14:12:15 -0700523
Ray Chen00c575a2009-08-28 14:12:15 -0700524 Uri blockingUri = baseUri.buildUpon().appendQueryParameter("blocking", "1")
Ray Chen13ed5752009-10-05 12:21:24 -0700525 .appendQueryParameter("orig_id", String.valueOf(origId))
526 .appendQueryParameter("group_id", String.valueOf(groupId)).build();
Ray Chen1ba38b62010-05-14 13:50:04 -0700527 if (c != null) c.close();
Ray Chen00c575a2009-08-28 14:12:15 -0700528 c = cr.query(blockingUri, PROJECTION, null, null, null);
529 // This happens when original image/video doesn't exist.
530 if (c == null) return null;
531
532 // Assuming thumbnail has been generated, at least original image exists.
533 if (kind == MICRO_KIND) {
Chih-Chung Chang2ca36192010-08-24 19:25:56 +0800534 synchronized (sThumbBufLock) {
535 if (sThumbBuf == null) {
536 sThumbBuf = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
537 }
538 if (thumbFile.getMiniThumbFromFile(origId, sThumbBuf) != null) {
539 bitmap = BitmapFactory.decodeByteArray(sThumbBuf, 0, sThumbBuf.length);
540 if (bitmap == null) {
541 Log.w(TAG, "couldn't decode byte array.");
542 }
Ray Chen00c575a2009-08-28 14:12:15 -0700543 }
544 }
545 } else if (kind == MINI_KIND) {
546 if (c.moveToFirst()) {
Ray Chenf9a243d2009-10-29 18:15:29 -0700547 bitmap = getMiniThumbFromFile(c, baseUri, cr, options);
Ray Chen00c575a2009-08-28 14:12:15 -0700548 }
549 } else {
550 throw new IllegalArgumentException("Unsupported kind: " + kind);
551 }
552
553 // We probably run out of space, so create the thumbnail in memory.
554 if (bitmap == null) {
Ray Chen44dcf652010-04-05 11:26:40 -0700555 Log.v(TAG, "Create the thumbnail in memory: origId=" + origId
556 + ", kind=" + kind + ", isVideo="+isVideo);
Ray Chen00c575a2009-08-28 14:12:15 -0700557 Uri uri = Uri.parse(
558 baseUri.buildUpon().appendPath(String.valueOf(origId))
559 .toString().replaceFirst("thumbnails", "media"));
Ray Chenef093cd2009-09-29 19:38:58 -0700560 if (filePath == null) {
Marco Nelissen9b150b72009-09-30 16:39:15 -0700561 if (c != null) c.close();
Ray Chen00c575a2009-08-28 14:12:15 -0700562 c = cr.query(uri, PROJECTION, null, null, null);
Ray Chenef093cd2009-09-29 19:38:58 -0700563 if (c == null || !c.moveToFirst()) {
564 return null;
565 }
566 filePath = c.getString(1);
567 }
568 if (isVideo) {
Ray Chen44dcf652010-04-05 11:26:40 -0700569 bitmap = ThumbnailUtils.createVideoThumbnail(filePath, kind);
Ray Chen00c575a2009-08-28 14:12:15 -0700570 } else {
Ray Chen44dcf652010-04-05 11:26:40 -0700571 bitmap = ThumbnailUtils.createImageThumbnail(filePath, kind);
Ray Chen00c575a2009-08-28 14:12:15 -0700572 }
573 }
574 } catch (SQLiteException ex) {
575 Log.w(TAG, ex);
576 } finally {
577 if (c != null) c.close();
Ray Chen1ba38b62010-05-14 13:50:04 -0700578 // To avoid file descriptor leak in application process.
579 thumbFile.deactivate();
580 thumbFile = null;
Ray Chen00c575a2009-08-28 14:12:15 -0700581 }
582 return bitmap;
583 }
584 }
585
586 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 * Contains meta data for all available images.
588 */
Ray Chen00c575a2009-08-28 14:12:15 -0700589 public static final class Images {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 public interface ImageColumns extends MediaColumns {
591 /**
592 * The description of the image
593 * <P>Type: TEXT</P>
594 */
595 public static final String DESCRIPTION = "description";
596
597 /**
598 * The picasa id of the image
599 * <P>Type: TEXT</P>
600 */
601 public static final String PICASA_ID = "picasa_id";
602
603 /**
604 * Whether the video should be published as public or private
605 * <P>Type: INTEGER</P>
606 */
607 public static final String IS_PRIVATE = "isprivate";
608
609 /**
610 * The latitude where the image was captured.
611 * <P>Type: DOUBLE</P>
612 */
613 public static final String LATITUDE = "latitude";
614
615 /**
616 * The longitude where the image was captured.
617 * <P>Type: DOUBLE</P>
618 */
619 public static final String LONGITUDE = "longitude";
620
621 /**
622 * The date & time that the image was taken in units
623 * of milliseconds since jan 1, 1970.
624 * <P>Type: INTEGER</P>
625 */
626 public static final String DATE_TAKEN = "datetaken";
627
628 /**
629 * The orientation for the image expressed as degrees.
630 * Only degrees 0, 90, 180, 270 will work.
631 * <P>Type: INTEGER</P>
632 */
633 public static final String ORIENTATION = "orientation";
634
635 /**
636 * The mini thumb id.
637 * <P>Type: INTEGER</P>
638 */
639 public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
640
641 /**
642 * The bucket id of the image. This is a read-only property that
643 * is automatically computed from the DATA column.
644 * <P>Type: TEXT</P>
645 */
646 public static final String BUCKET_ID = "bucket_id";
647
648 /**
649 * The bucket display name of the image. This is a read-only property that
650 * is automatically computed from the DATA column.
651 * <P>Type: TEXT</P>
652 */
653 public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
654 }
655
656 public static final class Media implements ImageColumns {
Ray Chen00c575a2009-08-28 14:12:15 -0700657 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
659 }
660
661 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection,
Ray Chen00c575a2009-08-28 14:12:15 -0700662 String where, String orderBy) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 return cr.query(uri, projection, where,
664 null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
665 }
666
667 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection,
Ray Chen00c575a2009-08-28 14:12:15 -0700668 String selection, String [] selectionArgs, String orderBy) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 return cr.query(uri, projection, selection,
670 selectionArgs, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
671 }
672
673 /**
674 * Retrieves an image for the given url as a {@link Bitmap}.
675 *
676 * @param cr The content resolver to use
677 * @param url The url of the image
678 * @throws FileNotFoundException
679 * @throws IOException
680 */
681 public static final Bitmap getBitmap(ContentResolver cr, Uri url)
Ray Chen00c575a2009-08-28 14:12:15 -0700682 throws FileNotFoundException, IOException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 InputStream input = cr.openInputStream(url);
684 Bitmap bitmap = BitmapFactory.decodeStream(input);
685 input.close();
686 return bitmap;
687 }
688
689 /**
690 * Insert an image and create a thumbnail for it.
691 *
692 * @param cr The content resolver to use
693 * @param imagePath The path to the image to insert
694 * @param name The name of the image
695 * @param description The description of the image
696 * @return The URL to the newly created image
697 * @throws FileNotFoundException
698 */
Ray Chen00c575a2009-08-28 14:12:15 -0700699 public static final String insertImage(ContentResolver cr, String imagePath,
700 String name, String description) throws FileNotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 // Check if file exists with a FileInputStream
702 FileInputStream stream = new FileInputStream(imagePath);
703 try {
Marco Nelissen2f189fa2009-06-30 10:32:00 -0700704 Bitmap bm = BitmapFactory.decodeFile(imagePath);
705 String ret = insertImage(cr, bm, name, description);
706 bm.recycle();
707 return ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 } finally {
709 try {
710 stream.close();
711 } catch (IOException e) {
712 }
713 }
714 }
715
716 private static final Bitmap StoreThumbnail(
717 ContentResolver cr,
718 Bitmap source,
719 long id,
720 float width, float height,
721 int kind) {
722 // create the matrix to scale it
723 Matrix matrix = new Matrix();
724
725 float scaleX = width / source.getWidth();
726 float scaleY = height / source.getHeight();
727
728 matrix.setScale(scaleX, scaleY);
729
730 Bitmap thumb = Bitmap.createBitmap(source, 0, 0,
731 source.getWidth(),
732 source.getHeight(), matrix,
733 true);
734
735 ContentValues values = new ContentValues(4);
736 values.put(Images.Thumbnails.KIND, kind);
737 values.put(Images.Thumbnails.IMAGE_ID, (int)id);
738 values.put(Images.Thumbnails.HEIGHT, thumb.getHeight());
739 values.put(Images.Thumbnails.WIDTH, thumb.getWidth());
740
741 Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values);
742
743 try {
744 OutputStream thumbOut = cr.openOutputStream(url);
745
746 thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut);
747 thumbOut.close();
748 return thumb;
749 }
750 catch (FileNotFoundException ex) {
751 return null;
752 }
753 catch (IOException ex) {
754 return null;
755 }
756 }
757
758 /**
759 * Insert an image and create a thumbnail for it.
760 *
761 * @param cr The content resolver to use
762 * @param source The stream to use for the image
763 * @param title The name of the image
764 * @param description The description of the image
765 * @return The URL to the newly created image, or <code>null</code> if the image failed to be stored
766 * for any reason.
767 */
768 public static final String insertImage(ContentResolver cr, Bitmap source,
Ray Chen00c575a2009-08-28 14:12:15 -0700769 String title, String description) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 ContentValues values = new ContentValues();
771 values.put(Images.Media.TITLE, title);
772 values.put(Images.Media.DESCRIPTION, description);
773 values.put(Images.Media.MIME_TYPE, "image/jpeg");
774
775 Uri url = null;
776 String stringUrl = null; /* value to be returned */
777
Ray Chen00c575a2009-08-28 14:12:15 -0700778 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 url = cr.insert(EXTERNAL_CONTENT_URI, values);
780
781 if (source != null) {
782 OutputStream imageOut = cr.openOutputStream(url);
783 try {
784 source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut);
785 } finally {
786 imageOut.close();
787 }
788
789 long id = ContentUris.parseId(url);
Ray Chen44dcf652010-04-05 11:26:40 -0700790 // Wait until MINI_KIND thumbnail is generated.
791 Bitmap miniThumb = Images.Thumbnails.getThumbnail(cr, id,
792 Images.Thumbnails.MINI_KIND, null);
793 // This is for backward compatibility.
794 Bitmap microThumb = StoreThumbnail(cr, miniThumb, id, 50F, 50F,
795 Images.Thumbnails.MICRO_KIND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 } else {
797 Log.e(TAG, "Failed to create thumbnail, removing original");
798 cr.delete(url, null, null);
799 url = null;
800 }
801 } catch (Exception e) {
802 Log.e(TAG, "Failed to insert image", e);
803 if (url != null) {
804 cr.delete(url, null, null);
805 url = null;
806 }
807 }
808
809 if (url != null) {
810 stringUrl = url.toString();
811 }
812
813 return stringUrl;
814 }
815
816 /**
817 * Get the content:// style URI for the image media table on the
818 * given volume.
819 *
820 * @param volumeName the name of the volume to get the URI for
821 * @return the URI to the image media table on the given volume
822 */
823 public static Uri getContentUri(String volumeName) {
824 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
825 "/images/media");
826 }
827
828 /**
829 * The content:// style URI for the internal storage.
830 */
831 public static final Uri INTERNAL_CONTENT_URI =
832 getContentUri("internal");
833
834 /**
835 * The content:// style URI for the "primary" external storage
836 * volume.
837 */
838 public static final Uri EXTERNAL_CONTENT_URI =
839 getContentUri("external");
840
841 /**
842 * The MIME type of of this directory of
843 * images. Note that each entry in this directory will have a standard
844 * image MIME type as appropriate -- for example, image/jpeg.
845 */
846 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/image";
847
848 /**
849 * The default sort order for this table
850 */
851 public static final String DEFAULT_SORT_ORDER = ImageColumns.BUCKET_DISPLAY_NAME;
Ray Chen00c575a2009-08-28 14:12:15 -0700852 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853
Ray Chen00c575a2009-08-28 14:12:15 -0700854 /**
855 * This class allows developers to query and get two kinds of thumbnails:
856 * MINI_KIND: 512 x 384 thumbnail
857 * MICRO_KIND: 96 x 96 thumbnail
858 */
859 public static class Thumbnails implements BaseColumns {
860 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
862 }
863
Ray Chen00c575a2009-08-28 14:12:15 -0700864 public static final Cursor queryMiniThumbnails(ContentResolver cr, Uri uri, int kind,
865 String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 return cr.query(uri, projection, "kind = " + kind, null, DEFAULT_SORT_ORDER);
867 }
868
Ray Chen00c575a2009-08-28 14:12:15 -0700869 public static final Cursor queryMiniThumbnail(ContentResolver cr, long origId, int kind,
870 String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 return cr.query(EXTERNAL_CONTENT_URI, projection,
872 IMAGE_ID + " = " + origId + " AND " + KIND + " = " +
873 kind, null, null);
874 }
875
876 /**
Ray Chenb9944192009-09-29 20:24:01 -0700877 * This method cancels the thumbnail request so clients waiting for getThumbnail will be
878 * interrupted and return immediately. Only the original process which made the getThumbnail
879 * requests can cancel their own requests.
880 *
881 * @param cr ContentResolver
882 * @param origId original image id
883 */
884 public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
Ray Chen13ed5752009-10-05 12:21:24 -0700885 InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI,
886 InternalThumbnails.DEFAULT_GROUP_ID);
Ray Chenb9944192009-09-29 20:24:01 -0700887 }
888
889 /**
Ray Chen00c575a2009-08-28 14:12:15 -0700890 * This method checks if the thumbnails of the specified image (origId) has been created.
891 * It will be blocked until the thumbnails are generated.
892 *
893 * @param cr ContentResolver used to dispatch queries to MediaProvider.
894 * @param origId Original image id associated with thumbnail of interest.
895 * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND.
896 * @param options this is only used for MINI_KIND when decoding the Bitmap
897 * @return A Bitmap instance. It could be null if the original image
898 * associated with origId doesn't exist or memory is not enough.
899 */
900 public static Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
901 BitmapFactory.Options options) {
Ray Chen13ed5752009-10-05 12:21:24 -0700902 return InternalThumbnails.getThumbnail(cr, origId,
903 InternalThumbnails.DEFAULT_GROUP_ID, kind, options,
904 EXTERNAL_CONTENT_URI, false);
905 }
906
907 /**
908 * This method cancels the thumbnail request so clients waiting for getThumbnail will be
909 * interrupted and return immediately. Only the original process which made the getThumbnail
910 * requests can cancel their own requests.
911 *
912 * @param cr ContentResolver
913 * @param origId original image id
914 * @param groupId the same groupId used in getThumbnail.
915 */
916 public static void cancelThumbnailRequest(ContentResolver cr, long origId, long groupId) {
917 InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI, groupId);
918 }
919
920 /**
921 * This method checks if the thumbnails of the specified image (origId) has been created.
922 * It will be blocked until the thumbnails are generated.
923 *
924 * @param cr ContentResolver used to dispatch queries to MediaProvider.
925 * @param origId Original image id associated with thumbnail of interest.
926 * @param groupId the id of group to which this request belongs
927 * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND.
928 * @param options this is only used for MINI_KIND when decoding the Bitmap
929 * @return A Bitmap instance. It could be null if the original image
930 * associated with origId doesn't exist or memory is not enough.
931 */
932 public static Bitmap getThumbnail(ContentResolver cr, long origId, long groupId,
933 int kind, BitmapFactory.Options options) {
934 return InternalThumbnails.getThumbnail(cr, origId, groupId, kind, options,
Ray Chen00c575a2009-08-28 14:12:15 -0700935 EXTERNAL_CONTENT_URI, false);
936 }
937
938 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 * Get the content:// style URI for the image media table on the
940 * given volume.
941 *
942 * @param volumeName the name of the volume to get the URI for
943 * @return the URI to the image media table on the given volume
944 */
945 public static Uri getContentUri(String volumeName) {
946 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
947 "/images/thumbnails");
948 }
949
950 /**
951 * The content:// style URI for the internal storage.
952 */
953 public static final Uri INTERNAL_CONTENT_URI =
954 getContentUri("internal");
955
956 /**
957 * The content:// style URI for the "primary" external storage
958 * volume.
959 */
960 public static final Uri EXTERNAL_CONTENT_URI =
961 getContentUri("external");
962
963 /**
964 * The default sort order for this table
965 */
966 public static final String DEFAULT_SORT_ORDER = "image_id ASC";
967
968 /**
969 * The data stream for the thumbnail
970 * <P>Type: DATA STREAM</P>
971 */
972 public static final String DATA = "_data";
973
974 /**
975 * The original image for the thumbnal
976 * <P>Type: INTEGER (ID from Images table)</P>
977 */
978 public static final String IMAGE_ID = "image_id";
979
980 /**
981 * The kind of the thumbnail
982 * <P>Type: INTEGER (One of the values below)</P>
983 */
984 public static final String KIND = "kind";
985
986 public static final int MINI_KIND = 1;
987 public static final int FULL_SCREEN_KIND = 2;
988 public static final int MICRO_KIND = 3;
Ray Chen00c575a2009-08-28 14:12:15 -0700989 /**
990 * The blob raw data of thumbnail
991 * <P>Type: DATA STREAM</P>
992 */
993 public static final String THUMB_DATA = "thumb_data";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994
995 /**
996 * The width of the thumbnal
997 * <P>Type: INTEGER (long)</P>
998 */
999 public static final String WIDTH = "width";
1000
1001 /**
1002 * The height of the thumbnail
1003 * <P>Type: INTEGER (long)</P>
1004 */
1005 public static final String HEIGHT = "height";
1006 }
1007 }
1008
1009 /**
1010 * Container for all audio content.
1011 */
1012 public static final class Audio {
1013 /**
1014 * Columns for audio file that show up in multiple tables.
1015 */
1016 public interface AudioColumns extends MediaColumns {
1017
1018 /**
1019 * A non human readable key calculated from the TITLE, used for
1020 * searching, sorting and grouping
1021 * <P>Type: TEXT</P>
1022 */
1023 public static final String TITLE_KEY = "title_key";
1024
1025 /**
1026 * The duration of the audio file, in ms
1027 * <P>Type: INTEGER (long)</P>
1028 */
1029 public static final String DURATION = "duration";
1030
1031 /**
1032 * The position, in ms, playback was at when playback for this file
1033 * was last stopped.
1034 * <P>Type: INTEGER (long)</P>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 */
1036 public static final String BOOKMARK = "bookmark";
1037
1038 /**
1039 * The id of the artist who created the audio file, if any
1040 * <P>Type: INTEGER (long)</P>
1041 */
1042 public static final String ARTIST_ID = "artist_id";
1043
1044 /**
1045 * The artist who created the audio file, if any
1046 * <P>Type: TEXT</P>
1047 */
1048 public static final String ARTIST = "artist";
1049
1050 /**
Marco Nelissenabc28192010-03-18 17:10:38 -07001051 * The artist credited for the album that contains the audio file
1052 * <P>Type: TEXT</P>
1053 * @hide
1054 */
1055 public static final String ALBUM_ARTIST = "album_artist";
1056
1057 /**
Marco Nelissenee35aff2011-01-06 11:12:17 -08001058 * Whether the song is part of a compilation
1059 * <P>Type: TEXT</P>
1060 * @hide
1061 */
1062 public static final String COMPILATION = "compilation";
1063
1064 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 * A non human readable key calculated from the ARTIST, used for
1066 * searching, sorting and grouping
1067 * <P>Type: TEXT</P>
1068 */
1069 public static final String ARTIST_KEY = "artist_key";
1070
1071 /**
1072 * The composer of the audio file, if any
1073 * <P>Type: TEXT</P>
1074 */
1075 public static final String COMPOSER = "composer";
1076
1077 /**
1078 * The id of the album the audio file is from, if any
1079 * <P>Type: INTEGER (long)</P>
1080 */
1081 public static final String ALBUM_ID = "album_id";
1082
1083 /**
1084 * The album the audio file is from, if any
1085 * <P>Type: TEXT</P>
1086 */
1087 public static final String ALBUM = "album";
1088
1089 /**
1090 * A non human readable key calculated from the ALBUM, used for
1091 * searching, sorting and grouping
1092 * <P>Type: TEXT</P>
1093 */
1094 public static final String ALBUM_KEY = "album_key";
1095
1096 /**
1097 * A URI to the album art, if any
1098 * <P>Type: TEXT</P>
1099 */
1100 public static final String ALBUM_ART = "album_art";
1101
1102 /**
1103 * The track number of this song on the album, if any.
1104 * This number encodes both the track number and the
1105 * disc number. For multi-disc sets, this number will
1106 * be 1xxx for tracks on the first disc, 2xxx for tracks
1107 * on the second disc, etc.
1108 * <P>Type: INTEGER</P>
1109 */
1110 public static final String TRACK = "track";
1111
1112 /**
1113 * The year the audio file was recorded, if any
1114 * <P>Type: INTEGER</P>
1115 */
1116 public static final String YEAR = "year";
1117
1118 /**
1119 * Non-zero if the audio file is music
1120 * <P>Type: INTEGER (boolean)</P>
1121 */
1122 public static final String IS_MUSIC = "is_music";
1123
1124 /**
1125 * Non-zero if the audio file is a podcast
1126 * <P>Type: INTEGER (boolean)</P>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 */
1128 public static final String IS_PODCAST = "is_podcast";
1129
1130 /**
1131 * Non-zero id the audio file may be a ringtone
1132 * <P>Type: INTEGER (boolean)</P>
1133 */
1134 public static final String IS_RINGTONE = "is_ringtone";
1135
1136 /**
1137 * Non-zero id the audio file may be an alarm
1138 * <P>Type: INTEGER (boolean)</P>
1139 */
1140 public static final String IS_ALARM = "is_alarm";
1141
1142 /**
1143 * Non-zero id the audio file may be a notification sound
1144 * <P>Type: INTEGER (boolean)</P>
1145 */
1146 public static final String IS_NOTIFICATION = "is_notification";
1147 }
1148
1149 /**
1150 * Converts a name to a "key" that can be used for grouping, sorting
1151 * and searching.
1152 * The rules that govern this conversion are:
1153 * - remove 'special' characters like ()[]'!?.,
1154 * - remove leading/trailing spaces
1155 * - convert everything to lowercase
1156 * - remove leading "the ", "an " and "a "
1157 * - remove trailing ", the|an|a"
1158 * - remove accents. This step leaves us with CollationKey data,
1159 * which is not human readable
1160 *
1161 * @param name The artist or album name to convert
1162 * @return The "key" for the given name.
1163 */
1164 public static String keyFor(String name) {
1165 if (name != null) {
Marco Nelissen816cf522009-07-06 09:19:10 -07001166 boolean sortfirst = false;
Marco Nelissen9a488b42010-01-04 15:09:03 -08001167 if (name.equals(UNKNOWN_STRING)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001168 return "\001";
1169 }
Marco Nelissen816cf522009-07-06 09:19:10 -07001170 // Check if the first character is \001. We use this to
1171 // force sorting of certain special files, like the silent ringtone.
1172 if (name.startsWith("\001")) {
1173 sortfirst = true;
1174 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 name = name.trim().toLowerCase();
1176 if (name.startsWith("the ")) {
1177 name = name.substring(4);
1178 }
1179 if (name.startsWith("an ")) {
1180 name = name.substring(3);
1181 }
1182 if (name.startsWith("a ")) {
1183 name = name.substring(2);
1184 }
1185 if (name.endsWith(", the") || name.endsWith(",the") ||
1186 name.endsWith(", an") || name.endsWith(",an") ||
1187 name.endsWith(", a") || name.endsWith(",a")) {
1188 name = name.substring(0, name.lastIndexOf(','));
1189 }
Marco Nelissene754e122009-05-22 12:16:58 -07001190 name = name.replaceAll("[\\[\\]\\(\\)\"'.,?!]", "").trim();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 if (name.length() > 0) {
1192 // Insert a separator between the characters to avoid
1193 // matches on a partial character. If we ever change
1194 // to start-of-word-only matches, this can be removed.
1195 StringBuilder b = new StringBuilder();
1196 b.append('.');
1197 int nl = name.length();
1198 for (int i = 0; i < nl; i++) {
1199 b.append(name.charAt(i));
1200 b.append('.');
1201 }
1202 name = b.toString();
Marco Nelissen816cf522009-07-06 09:19:10 -07001203 String key = DatabaseUtils.getCollationKey(name);
1204 if (sortfirst) {
1205 key = "\001" + key;
1206 }
1207 return key;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 } else {
1209 return "";
1210 }
1211 }
1212 return null;
1213 }
1214
1215 public static final class Media implements AudioColumns {
1216 /**
1217 * Get the content:// style URI for the audio media table on the
1218 * given volume.
1219 *
1220 * @param volumeName the name of the volume to get the URI for
1221 * @return the URI to the audio media table on the given volume
1222 */
1223 public static Uri getContentUri(String volumeName) {
1224 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1225 "/audio/media");
1226 }
1227
1228 public static Uri getContentUriForPath(String path) {
1229 return (path.startsWith(Environment.getExternalStorageDirectory().getPath()) ?
1230 EXTERNAL_CONTENT_URI : INTERNAL_CONTENT_URI);
1231 }
1232
1233 /**
1234 * The content:// style URI for the internal storage.
1235 */
1236 public static final Uri INTERNAL_CONTENT_URI =
1237 getContentUri("internal");
1238
1239 /**
1240 * The content:// style URI for the "primary" external storage
1241 * volume.
1242 */
1243 public static final Uri EXTERNAL_CONTENT_URI =
1244 getContentUri("external");
1245
1246 /**
1247 * The MIME type for this table.
1248 */
1249 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
1250
1251 /**
1252 * The default sort order for this table
1253 */
Marco Nelissen816cf522009-07-06 09:19:10 -07001254 public static final String DEFAULT_SORT_ORDER = TITLE_KEY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255
1256 /**
1257 * Activity Action: Start SoundRecorder application.
1258 * <p>Input: nothing.
1259 * <p>Output: An uri to the recorded sound stored in the Media Library
1260 * if the recording was successful.
1261 * May also contain the extra EXTRA_MAX_BYTES.
1262 * @see #EXTRA_MAX_BYTES
1263 */
1264 public static final String RECORD_SOUND_ACTION =
1265 "android.provider.MediaStore.RECORD_SOUND";
1266
1267 /**
1268 * The name of the Intent-extra used to define a maximum file size for
1269 * a recording made by the SoundRecorder application.
1270 *
1271 * @see #RECORD_SOUND_ACTION
1272 */
1273 public static final String EXTRA_MAX_BYTES =
1274 "android.provider.MediaStore.extra.MAX_BYTES";
1275 }
1276
1277 /**
1278 * Columns representing an audio genre
1279 */
1280 public interface GenresColumns {
1281 /**
1282 * The name of the genre
1283 * <P>Type: TEXT</P>
1284 */
1285 public static final String NAME = "name";
1286 }
1287
1288 /**
1289 * Contains all genres for audio files
1290 */
1291 public static final class Genres implements BaseColumns, GenresColumns {
1292 /**
1293 * Get the content:// style URI for the audio genres table on the
1294 * given volume.
1295 *
1296 * @param volumeName the name of the volume to get the URI for
1297 * @return the URI to the audio genres table on the given volume
1298 */
1299 public static Uri getContentUri(String volumeName) {
1300 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1301 "/audio/genres");
1302 }
1303
1304 /**
Mike Lockwoodbdb05df2010-09-26 12:33:25 -04001305 * Get the content:// style URI for querying the genres of an audio file.
1306 *
1307 * @param volumeName the name of the volume to get the URI for
1308 * @param audioId the ID of the audio file for which to retrieve the genres
1309 * @return the URI to for querying the genres for the audio file
1310 * with the given the volume and audioID
1311 */
1312 public static Uri getContentUriForAudioId(String volumeName, int audioId) {
1313 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1314 "/audio/media/" + audioId + "/genres");
1315 }
1316
1317 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 * The content:// style URI for the internal storage.
1319 */
1320 public static final Uri INTERNAL_CONTENT_URI =
1321 getContentUri("internal");
1322
1323 /**
1324 * The content:// style URI for the "primary" external storage
1325 * volume.
1326 */
1327 public static final Uri EXTERNAL_CONTENT_URI =
1328 getContentUri("external");
1329
1330 /**
1331 * The MIME type for this table.
1332 */
1333 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/genre";
1334
1335 /**
1336 * The MIME type for entries in this table.
1337 */
1338 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/genre";
1339
1340 /**
1341 * The default sort order for this table
1342 */
1343 public static final String DEFAULT_SORT_ORDER = NAME;
1344
1345 /**
1346 * Sub-directory of each genre containing all members.
1347 */
1348 public static final class Members implements AudioColumns {
1349
1350 public static final Uri getContentUri(String volumeName,
1351 long genreId) {
1352 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
1353 + "/audio/genres/" + genreId + "/members");
1354 }
1355
1356 /**
1357 * A subdirectory of each genre containing all member audio files.
1358 */
1359 public static final String CONTENT_DIRECTORY = "members";
1360
1361 /**
1362 * The default sort order for this table
1363 */
Marco Nelissen816cf522009-07-06 09:19:10 -07001364 public static final String DEFAULT_SORT_ORDER = TITLE_KEY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365
1366 /**
1367 * The ID of the audio file
1368 * <P>Type: INTEGER (long)</P>
1369 */
1370 public static final String AUDIO_ID = "audio_id";
1371
1372 /**
1373 * The ID of the genre
1374 * <P>Type: INTEGER (long)</P>
1375 */
1376 public static final String GENRE_ID = "genre_id";
1377 }
1378 }
1379
1380 /**
1381 * Columns representing a playlist
1382 */
1383 public interface PlaylistsColumns {
1384 /**
1385 * The name of the playlist
1386 * <P>Type: TEXT</P>
1387 */
1388 public static final String NAME = "name";
1389
1390 /**
1391 * The data stream for the playlist file
1392 * <P>Type: DATA STREAM</P>
1393 */
1394 public static final String DATA = "_data";
1395
1396 /**
1397 * The time the file was added to the media provider
1398 * Units are seconds since 1970.
1399 * <P>Type: INTEGER (long)</P>
1400 */
1401 public static final String DATE_ADDED = "date_added";
1402
1403 /**
1404 * The time the file was last modified
1405 * Units are seconds since 1970.
1406 * NOTE: This is for internal use by the media scanner. Do not modify this field.
1407 * <P>Type: INTEGER (long)</P>
1408 */
1409 public static final String DATE_MODIFIED = "date_modified";
1410 }
1411
1412 /**
1413 * Contains playlists for audio files
1414 */
1415 public static final class Playlists implements BaseColumns,
1416 PlaylistsColumns {
1417 /**
1418 * Get the content:// style URI for the audio playlists table on the
1419 * given volume.
1420 *
1421 * @param volumeName the name of the volume to get the URI for
1422 * @return the URI to the audio playlists table on the given volume
1423 */
1424 public static Uri getContentUri(String volumeName) {
1425 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1426 "/audio/playlists");
1427 }
1428
1429 /**
1430 * The content:// style URI for the internal storage.
1431 */
1432 public static final Uri INTERNAL_CONTENT_URI =
1433 getContentUri("internal");
1434
1435 /**
1436 * The content:// style URI for the "primary" external storage
1437 * volume.
1438 */
1439 public static final Uri EXTERNAL_CONTENT_URI =
1440 getContentUri("external");
1441
1442 /**
1443 * The MIME type for this table.
1444 */
1445 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/playlist";
1446
1447 /**
1448 * The MIME type for entries in this table.
1449 */
1450 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/playlist";
1451
1452 /**
1453 * The default sort order for this table
1454 */
1455 public static final String DEFAULT_SORT_ORDER = NAME;
1456
1457 /**
1458 * Sub-directory of each playlist containing all members.
1459 */
1460 public static final class Members implements AudioColumns {
1461 public static final Uri getContentUri(String volumeName,
1462 long playlistId) {
1463 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
1464 + "/audio/playlists/" + playlistId + "/members");
1465 }
1466
1467 /**
Marco Nelissene3d05fc2009-12-09 16:01:46 -08001468 * Convenience method to move a playlist item to a new location
1469 * @param res The content resolver to use
1470 * @param playlistId The numeric id of the playlist
1471 * @param from The position of the item to move
1472 * @param to The position to move the item to
1473 * @return true on success
Marco Nelissene3d05fc2009-12-09 16:01:46 -08001474 */
1475 public static final boolean moveItem(ContentResolver res,
1476 long playlistId, int from, int to) {
1477 Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external",
1478 playlistId)
1479 .buildUpon()
1480 .appendEncodedPath(String.valueOf(from))
1481 .appendQueryParameter("move", "true")
1482 .build();
1483 ContentValues values = new ContentValues();
1484 values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, to);
1485 return res.update(uri, values, null, null) != 0;
1486 }
1487
1488 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 * The ID within the playlist.
1490 */
1491 public static final String _ID = "_id";
1492
1493 /**
1494 * A subdirectory of each playlist containing all member audio
1495 * files.
1496 */
1497 public static final String CONTENT_DIRECTORY = "members";
1498
1499 /**
1500 * The ID of the audio file
1501 * <P>Type: INTEGER (long)</P>
1502 */
1503 public static final String AUDIO_ID = "audio_id";
1504
1505 /**
1506 * The ID of the playlist
1507 * <P>Type: INTEGER (long)</P>
1508 */
1509 public static final String PLAYLIST_ID = "playlist_id";
1510
1511 /**
1512 * The order of the songs in the playlist
1513 * <P>Type: INTEGER (long)></P>
1514 */
1515 public static final String PLAY_ORDER = "play_order";
1516
1517 /**
1518 * The default sort order for this table
1519 */
1520 public static final String DEFAULT_SORT_ORDER = PLAY_ORDER;
1521 }
1522 }
1523
1524 /**
1525 * Columns representing an artist
1526 */
1527 public interface ArtistColumns {
1528 /**
1529 * The artist who created the audio file, if any
1530 * <P>Type: TEXT</P>
1531 */
1532 public static final String ARTIST = "artist";
1533
1534 /**
1535 * A non human readable key calculated from the ARTIST, used for
1536 * searching, sorting and grouping
1537 * <P>Type: TEXT</P>
1538 */
1539 public static final String ARTIST_KEY = "artist_key";
1540
1541 /**
1542 * The number of albums in the database for this artist
1543 */
1544 public static final String NUMBER_OF_ALBUMS = "number_of_albums";
1545
1546 /**
1547 * The number of albums in the database for this artist
1548 */
1549 public static final String NUMBER_OF_TRACKS = "number_of_tracks";
1550 }
1551
1552 /**
1553 * Contains artists for audio files
1554 */
1555 public static final class Artists implements BaseColumns, ArtistColumns {
1556 /**
1557 * Get the content:// style URI for the artists table on the
1558 * given volume.
1559 *
1560 * @param volumeName the name of the volume to get the URI for
1561 * @return the URI to the audio artists table on the given volume
1562 */
1563 public static Uri getContentUri(String volumeName) {
1564 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1565 "/audio/artists");
1566 }
1567
1568 /**
1569 * The content:// style URI for the internal storage.
1570 */
1571 public static final Uri INTERNAL_CONTENT_URI =
1572 getContentUri("internal");
1573
1574 /**
1575 * The content:// style URI for the "primary" external storage
1576 * volume.
1577 */
1578 public static final Uri EXTERNAL_CONTENT_URI =
1579 getContentUri("external");
1580
1581 /**
1582 * The MIME type for this table.
1583 */
1584 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/artists";
1585
1586 /**
1587 * The MIME type for entries in this table.
1588 */
1589 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/artist";
1590
1591 /**
1592 * The default sort order for this table
1593 */
1594 public static final String DEFAULT_SORT_ORDER = ARTIST_KEY;
1595
1596 /**
1597 * Sub-directory of each artist containing all albums on which
1598 * a song by the artist appears.
1599 */
1600 public static final class Albums implements AlbumColumns {
1601 public static final Uri getContentUri(String volumeName,
1602 long artistId) {
1603 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
1604 + "/audio/artists/" + artistId + "/albums");
1605 }
1606 }
1607 }
1608
1609 /**
1610 * Columns representing an album
1611 */
1612 public interface AlbumColumns {
1613
1614 /**
1615 * The id for the album
1616 * <P>Type: INTEGER</P>
1617 */
1618 public static final String ALBUM_ID = "album_id";
1619
1620 /**
1621 * The album on which the audio file appears, if any
1622 * <P>Type: TEXT</P>
1623 */
1624 public static final String ALBUM = "album";
1625
1626 /**
1627 * The artist whose songs appear on this album
1628 * <P>Type: TEXT</P>
1629 */
1630 public static final String ARTIST = "artist";
1631
1632 /**
1633 * The number of songs on this album
1634 * <P>Type: INTEGER</P>
1635 */
1636 public static final String NUMBER_OF_SONGS = "numsongs";
1637
1638 /**
1639 * This column is available when getting album info via artist,
1640 * and indicates the number of songs on the album by the given
1641 * artist.
1642 * <P>Type: INTEGER</P>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 */
1644 public static final String NUMBER_OF_SONGS_FOR_ARTIST = "numsongs_by_artist";
1645
1646 /**
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07001647 * The year in which the earliest songs
1648 * on this album were released. This will often
1649 * be the same as {@link #LAST_YEAR}, but for compilation albums
1650 * they might differ.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 * <P>Type: INTEGER</P>
1652 */
1653 public static final String FIRST_YEAR = "minyear";
Ray Chen00c575a2009-08-28 14:12:15 -07001654
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07001655 /**
1656 * The year in which the latest songs
1657 * on this album were released. This will often
1658 * be the same as {@link #FIRST_YEAR}, but for compilation albums
1659 * they might differ.
1660 * <P>Type: INTEGER</P>
1661 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 public static final String LAST_YEAR = "maxyear";
1663
1664 /**
1665 * A non human readable key calculated from the ALBUM, used for
1666 * searching, sorting and grouping
1667 * <P>Type: TEXT</P>
1668 */
1669 public static final String ALBUM_KEY = "album_key";
1670
1671 /**
1672 * Cached album art.
1673 * <P>Type: TEXT</P>
1674 */
1675 public static final String ALBUM_ART = "album_art";
1676 }
1677
1678 /**
1679 * Contains artists for audio files
1680 */
1681 public static final class Albums implements BaseColumns, AlbumColumns {
1682 /**
1683 * Get the content:// style URI for the albums table on the
1684 * given volume.
1685 *
1686 * @param volumeName the name of the volume to get the URI for
1687 * @return the URI to the audio albums table on the given volume
1688 */
1689 public static Uri getContentUri(String volumeName) {
1690 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1691 "/audio/albums");
1692 }
1693
1694 /**
1695 * The content:// style URI for the internal storage.
1696 */
1697 public static final Uri INTERNAL_CONTENT_URI =
1698 getContentUri("internal");
1699
1700 /**
1701 * The content:// style URI for the "primary" external storage
1702 * volume.
1703 */
1704 public static final Uri EXTERNAL_CONTENT_URI =
1705 getContentUri("external");
1706
1707 /**
1708 * The MIME type for this table.
1709 */
1710 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/albums";
1711
1712 /**
1713 * The MIME type for entries in this table.
1714 */
1715 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/album";
1716
1717 /**
1718 * The default sort order for this table
1719 */
1720 public static final String DEFAULT_SORT_ORDER = ALBUM_KEY;
1721 }
1722 }
1723
1724 public static final class Video {
1725
1726 /**
1727 * The default sort order for this table.
1728 */
1729 public static final String DEFAULT_SORT_ORDER = MediaColumns.DISPLAY_NAME;
1730
Ray Chen00c575a2009-08-28 14:12:15 -07001731 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001732 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
1733 }
1734
1735 public interface VideoColumns extends MediaColumns {
1736
1737 /**
1738 * The duration of the video file, in ms
1739 * <P>Type: INTEGER (long)</P>
1740 */
1741 public static final String DURATION = "duration";
1742
1743 /**
1744 * The artist who created the video file, if any
1745 * <P>Type: TEXT</P>
1746 */
1747 public static final String ARTIST = "artist";
1748
1749 /**
1750 * The album the video file is from, if any
1751 * <P>Type: TEXT</P>
1752 */
1753 public static final String ALBUM = "album";
1754
1755 /**
1756 * The resolution of the video file, formatted as "XxY"
1757 * <P>Type: TEXT</P>
1758 */
1759 public static final String RESOLUTION = "resolution";
1760
1761 /**
1762 * The description of the video recording
1763 * <P>Type: TEXT</P>
1764 */
1765 public static final String DESCRIPTION = "description";
1766
1767 /**
1768 * Whether the video should be published as public or private
1769 * <P>Type: INTEGER</P>
1770 */
1771 public static final String IS_PRIVATE = "isprivate";
1772
1773 /**
1774 * The user-added tags associated with a video
1775 * <P>Type: TEXT</P>
1776 */
1777 public static final String TAGS = "tags";
1778
1779 /**
1780 * The YouTube category of the video
1781 * <P>Type: TEXT</P>
1782 */
1783 public static final String CATEGORY = "category";
1784
1785 /**
1786 * The language of the video
1787 * <P>Type: TEXT</P>
1788 */
1789 public static final String LANGUAGE = "language";
1790
1791 /**
1792 * The latitude where the image was captured.
1793 * <P>Type: DOUBLE</P>
1794 */
1795 public static final String LATITUDE = "latitude";
1796
1797 /**
1798 * The longitude where the image was captured.
1799 * <P>Type: DOUBLE</P>
1800 */
1801 public static final String LONGITUDE = "longitude";
1802
1803 /**
1804 * The date & time that the image was taken in units
1805 * of milliseconds since jan 1, 1970.
1806 * <P>Type: INTEGER</P>
1807 */
1808 public static final String DATE_TAKEN = "datetaken";
1809
1810 /**
1811 * The mini thumb id.
1812 * <P>Type: INTEGER</P>
1813 */
1814 public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
1815
1816 /**
1817 * The bucket id of the video. This is a read-only property that
1818 * is automatically computed from the DATA column.
1819 * <P>Type: TEXT</P>
1820 */
1821 public static final String BUCKET_ID = "bucket_id";
1822
1823 /**
1824 * The bucket display name of the video. This is a read-only property that
1825 * is automatically computed from the DATA column.
1826 * <P>Type: TEXT</P>
1827 */
1828 public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
1829
1830 /**
1831 * The bookmark for the video. Time in ms. Represents the location in the video that the
1832 * video should start playing at the next time it is opened. If the value is null or
1833 * out of the range 0..DURATION-1 then the video should start playing from the
1834 * beginning.
1835 * <P>Type: INTEGER</P>
1836 */
1837 public static final String BOOKMARK = "bookmark";
1838 }
1839
1840 public static final class Media implements VideoColumns {
1841 /**
1842 * Get the content:// style URI for the video media table on the
1843 * given volume.
1844 *
1845 * @param volumeName the name of the volume to get the URI for
1846 * @return the URI to the video media table on the given volume
1847 */
1848 public static Uri getContentUri(String volumeName) {
1849 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1850 "/video/media");
1851 }
1852
1853 /**
1854 * The content:// style URI for the internal storage.
1855 */
1856 public static final Uri INTERNAL_CONTENT_URI =
1857 getContentUri("internal");
1858
1859 /**
1860 * The content:// style URI for the "primary" external storage
1861 * volume.
1862 */
1863 public static final Uri EXTERNAL_CONTENT_URI =
1864 getContentUri("external");
1865
1866 /**
1867 * The MIME type for this table.
1868 */
1869 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/video";
1870
1871 /**
1872 * The default sort order for this table
1873 */
1874 public static final String DEFAULT_SORT_ORDER = TITLE;
1875 }
Ray Chen00c575a2009-08-28 14:12:15 -07001876
1877 /**
1878 * This class allows developers to query and get two kinds of thumbnails:
1879 * MINI_KIND: 512 x 384 thumbnail
1880 * MICRO_KIND: 96 x 96 thumbnail
1881 *
1882 */
1883 public static class Thumbnails implements BaseColumns {
1884 /**
Ray Chenb9944192009-09-29 20:24:01 -07001885 * This method cancels the thumbnail request so clients waiting for getThumbnail will be
1886 * interrupted and return immediately. Only the original process which made the getThumbnail
1887 * requests can cancel their own requests.
1888 *
1889 * @param cr ContentResolver
1890 * @param origId original video id
1891 */
1892 public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
Ray Chen13ed5752009-10-05 12:21:24 -07001893 InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI,
1894 InternalThumbnails.DEFAULT_GROUP_ID);
Ray Chenb9944192009-09-29 20:24:01 -07001895 }
1896
1897 /**
Ray Chen00c575a2009-08-28 14:12:15 -07001898 * This method checks if the thumbnails of the specified image (origId) has been created.
1899 * It will be blocked until the thumbnails are generated.
1900 *
1901 * @param cr ContentResolver used to dispatch queries to MediaProvider.
1902 * @param origId Original image id associated with thumbnail of interest.
Ray Chen13ed5752009-10-05 12:21:24 -07001903 * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND.
1904 * @param options this is only used for MINI_KIND when decoding the Bitmap
1905 * @return A Bitmap instance. It could be null if the original image
1906 * associated with origId doesn't exist or memory is not enough.
1907 */
1908 public static Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
1909 BitmapFactory.Options options) {
1910 return InternalThumbnails.getThumbnail(cr, origId,
1911 InternalThumbnails.DEFAULT_GROUP_ID, kind, options,
1912 EXTERNAL_CONTENT_URI, true);
1913 }
1914
1915 /**
1916 * This method checks if the thumbnails of the specified image (origId) has been created.
1917 * It will be blocked until the thumbnails are generated.
1918 *
1919 * @param cr ContentResolver used to dispatch queries to MediaProvider.
1920 * @param origId Original image id associated with thumbnail of interest.
1921 * @param groupId the id of group to which this request belongs
Ray Chen00c575a2009-08-28 14:12:15 -07001922 * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND
1923 * @param options this is only used for MINI_KIND when decoding the Bitmap
1924 * @return A Bitmap instance. It could be null if the original image associated with
1925 * origId doesn't exist or memory is not enough.
1926 */
Ray Chen13ed5752009-10-05 12:21:24 -07001927 public static Bitmap getThumbnail(ContentResolver cr, long origId, long groupId,
1928 int kind, BitmapFactory.Options options) {
1929 return InternalThumbnails.getThumbnail(cr, origId, groupId, kind, options,
Ray Chen00c575a2009-08-28 14:12:15 -07001930 EXTERNAL_CONTENT_URI, true);
1931 }
1932
1933 /**
Ray Chen13ed5752009-10-05 12:21:24 -07001934 * This method cancels the thumbnail request so clients waiting for getThumbnail will be
1935 * interrupted and return immediately. Only the original process which made the getThumbnail
1936 * requests can cancel their own requests.
1937 *
1938 * @param cr ContentResolver
1939 * @param origId original video id
1940 * @param groupId the same groupId used in getThumbnail.
1941 */
1942 public static void cancelThumbnailRequest(ContentResolver cr, long origId, long groupId) {
1943 InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI, groupId);
1944 }
1945
1946 /**
Ray Chen00c575a2009-08-28 14:12:15 -07001947 * Get the content:// style URI for the image media table on the
1948 * given volume.
1949 *
1950 * @param volumeName the name of the volume to get the URI for
1951 * @return the URI to the image media table on the given volume
1952 */
1953 public static Uri getContentUri(String volumeName) {
1954 return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
1955 "/video/thumbnails");
1956 }
1957
1958 /**
1959 * The content:// style URI for the internal storage.
1960 */
1961 public static final Uri INTERNAL_CONTENT_URI =
1962 getContentUri("internal");
1963
1964 /**
1965 * The content:// style URI for the "primary" external storage
1966 * volume.
1967 */
1968 public static final Uri EXTERNAL_CONTENT_URI =
1969 getContentUri("external");
1970
1971 /**
1972 * The default sort order for this table
1973 */
1974 public static final String DEFAULT_SORT_ORDER = "video_id ASC";
1975
1976 /**
1977 * The data stream for the thumbnail
1978 * <P>Type: DATA STREAM</P>
1979 */
1980 public static final String DATA = "_data";
1981
1982 /**
1983 * The original image for the thumbnal
1984 * <P>Type: INTEGER (ID from Video table)</P>
1985 */
1986 public static final String VIDEO_ID = "video_id";
1987
1988 /**
1989 * The kind of the thumbnail
1990 * <P>Type: INTEGER (One of the values below)</P>
1991 */
1992 public static final String KIND = "kind";
1993
1994 public static final int MINI_KIND = 1;
1995 public static final int FULL_SCREEN_KIND = 2;
1996 public static final int MICRO_KIND = 3;
1997
1998 /**
1999 * The width of the thumbnal
2000 * <P>Type: INTEGER (long)</P>
2001 */
2002 public static final String WIDTH = "width";
2003
2004 /**
2005 * The height of the thumbnail
2006 * <P>Type: INTEGER (long)</P>
2007 */
2008 public static final String HEIGHT = "height";
2009 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002010 }
2011
2012 /**
2013 * Uri for querying the state of the media scanner.
2014 */
2015 public static Uri getMediaScannerUri() {
2016 return Uri.parse(CONTENT_AUTHORITY_SLASH + "none/media_scanner");
2017 }
2018
2019 /**
2020 * Name of current volume being scanned by the media scanner.
2021 */
2022 public static final String MEDIA_SCANNER_VOLUME = "volume";
Karl Ostmo8ce072d2010-01-30 15:15:39 -06002023
2024 /**
2025 * Name of the file signaling the media scanner to ignore media in the containing directory
2026 * and its subdirectories. Developers should use this to avoid application graphics showing
2027 * up in the Gallery and likewise prevent application sounds and music from showing up in
2028 * the Music app.
2029 */
2030 public static final String MEDIA_IGNORE_FILENAME = ".nomedia";
Marco Nelissen3822f732011-02-03 10:59:30 -08002031
2032 /**
2033 * Get the media provider's version.
2034 * Applications that import data from the media provider into their own caches
2035 * can use this to detect that the media provider changed, and reimport data
2036 * as needed. No other assumptions should be made about the meaning of the version.
2037 * @param context Context to use for performing the query.
2038 * @return A version string, or null if the version could not be determined.
Marco Nelissen3822f732011-02-03 10:59:30 -08002039 */
2040 public static String getVersion(Context context) {
2041 Cursor c = context.getContentResolver().query(
2042 Uri.parse(CONTENT_AUTHORITY_SLASH + "none/version"),
2043 null, null, null, null);
2044 if (c != null) {
2045 try {
2046 if (c.moveToFirst()) {
2047 return c.getString(0);
2048 }
2049 } finally {
2050 c.close();
2051 }
2052 }
2053 return null;
2054 }
2055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002056}