blob: 643307eb89ae2850bd27d93df368f84b12f02711 [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
Jeff Sharkey9efa7b82018-12-07 17:15:36 -070019import android.annotation.BytesLong;
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -070020import android.annotation.CurrentTimeMillisLong;
21import android.annotation.CurrentTimeSecondsLong;
Jeff Sharkey5cc407f2019-01-04 16:09:18 -070022import android.annotation.DurationMillisLong;
Jeff Sharkeyc8e49242018-11-02 14:34:44 -060023import android.annotation.IntRange;
Jeff Sharkey30b77bc2018-07-27 20:56:34 -060024import android.annotation.NonNull;
25import android.annotation.Nullable;
Jeff Sharkey9efa7b82018-12-07 17:15:36 -070026import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.annotation.SdkConstant;
28import android.annotation.SdkConstant.SdkConstantType;
Jeff Sharkey9efa7b82018-12-07 17:15:36 -070029import android.annotation.TestApi;
Mathew Inwood6750f2e2018-08-10 09:29:25 +010030import android.annotation.UnsupportedAppUsage;
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -060031import android.app.Activity;
32import android.app.AppGlobals;
Jeff Sharkey30b77bc2018-07-27 20:56:34 -060033import android.content.ClipData;
Garfield Tan92b96ba2016-11-01 14:33:48 -070034import android.content.ContentProviderClient;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.content.ContentUris;
Jeff Sharkey9d0843d2013-05-07 12:41:33 -070037import android.content.ContentValues;
Marco Nelissen3822f732011-02-03 10:59:30 -080038import android.content.Context;
Jorim Jaggid9449862015-05-29 14:49:08 -070039import android.content.Intent;
Garfield Tan92b96ba2016-11-01 14:33:48 -070040import android.content.UriPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.database.Cursor;
42import android.database.DatabaseUtils;
43import android.graphics.Bitmap;
44import android.graphics.BitmapFactory;
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -070045import android.graphics.ImageDecoder;
Jeff Sharkey30b77bc2018-07-27 20:56:34 -060046import android.graphics.Point;
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -070047import android.graphics.PostProcessor;
Jeff Sharkey33e70bd2018-12-04 11:28:11 -070048import android.media.ExifInterface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.net.Uri;
Garfield Tan92b96ba2016-11-01 14:33:48 -070050import android.os.Bundle;
Jeff Sharkey30b77bc2018-07-27 20:56:34 -060051import android.os.CancellationSignal;
Jeff Sharkeyc8e49242018-11-02 14:34:44 -060052import android.os.Environment;
Jeff Sharkey8559e652019-01-20 11:21:59 -070053import android.os.FileUtils;
Jeff Sharkey52827962018-10-18 14:44:41 -060054import android.os.OperationCanceledException;
Jeff Sharkeyc8e49242018-11-02 14:34:44 -060055import android.os.ParcelFileDescriptor;
Garfield Tan92b96ba2016-11-01 14:33:48 -070056import android.os.RemoteException;
Jeff Sharkeyc8e49242018-11-02 14:34:44 -060057import android.os.UserHandle;
Jeff Sharkeydc50d4c2018-12-10 18:28:56 -070058import android.os.UserManager;
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -060059import android.os.storage.StorageManager;
60import android.os.storage.StorageVolume;
61import android.os.storage.VolumeInfo;
Jorim Jaggid9449862015-05-29 14:49:08 -070062import android.service.media.CameraPrewarmService;
Jeff Sharkeyc8e49242018-11-02 14:34:44 -060063import android.text.TextUtils;
Jeff Sharkey5cc407f2019-01-04 16:09:18 -070064import android.text.format.DateUtils;
Jeff Sharkey30b77bc2018-07-27 20:56:34 -060065import android.util.ArrayMap;
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -060066import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.util.Log;
68
Jeff Sharkey30b77bc2018-07-27 20:56:34 -060069import com.android.internal.annotations.GuardedBy;
70
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -060071import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import java.io.FileInputStream;
73import java.io.FileNotFoundException;
74import java.io.IOException;
75import java.io.InputStream;
76import java.io.OutputStream;
Jeff Sharkey3f64ec52019-01-22 13:19:40 -070077import java.util.ArrayList;
78import java.util.Collection;
Garfield Tan92b96ba2016-11-01 14:33:48 -070079import java.util.List;
Jeff Sharkeyc8e49242018-11-02 14:34:44 -060080import java.util.Objects;
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -060081import java.util.Set;
Sudheer Shankaa50f1a32018-12-07 01:15:46 -080082import java.util.regex.Pattern;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083
84/**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -070085 * The contract between the media provider and applications. Contains
86 * definitions for the supported URIs and columns.
87 * <p>
88 * The media provider provides an indexed collection of common media types, such
89 * as {@link Audio}, {@link Video}, and {@link Images}, from any attached
90 * storage devices. Each collection is organized based on the primary MIME type
91 * of the underlying content; for example, {@code image/*} content is indexed
92 * under {@link Images}. The {@link Files} collection provides a broad view
93 * across all collections, and does not filter by MIME type.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 */
Ray Chen00c575a2009-08-28 14:12:15 -070095public final class MediaStore {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 private final static String TAG = "MediaStore";
97
Jeff Sharkeybc2ae002018-07-31 10:45:37 -060098 /** The authority for the media provider */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 public static final String AUTHORITY = "media";
Jeff Sharkeybc2ae002018-07-31 10:45:37 -0600100 /** A content:// style uri to the authority for the media provider */
101 public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102
Jeff Sharkey36ee3622019-01-23 10:55:29 -0700103 /**
104 * Volume name used for content on "internal" storage of device. This
105 * volume contains media distributed with the device, such as built-in
106 * ringtones and wallpapers.
107 */
Jeff Sharkey8559e652019-01-20 11:21:59 -0700108 public static final String VOLUME_INTERNAL = "internal";
Jeff Sharkey36ee3622019-01-23 10:55:29 -0700109
110 /**
111 * Volume name used for content on "external" storage of device. This only
112 * includes media on the primary shared storage device; the contents of any
113 * secondary storage devices can be obtained using
114 * {@link #getAllVolumeNames(Context)}.
115 */
Jeff Sharkey8559e652019-01-20 11:21:59 -0700116 public static final String VOLUME_EXTERNAL = "external";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117
Jeff Sharkeycb269aac2019-01-25 11:15:38 -0700118 /** {@hide} */ @TestApi
119 public static final String SCAN_FILE_CALL = "scan_file";
120 /** {@hide} */ @TestApi
121 public static final String SCAN_VOLUME_CALL = "scan_volume";
122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 /**
Sudheer Shankacae41c42019-02-04 18:16:15 -0800124 * Extra used with {@link #SCAN_FILE_CALL} or {@link #SCAN_VOLUME_CALL} to indicate that
125 * the file path originated from shell.
126 *
127 * {@hide}
128 */
129 @TestApi
130 public static final String EXTRA_ORIGINATED_FROM_SHELL =
131 "android.intent.extra.originated_from_shell";
132
133 /**
Marco Nelissenca78f3d2012-01-27 09:43:20 -0800134 * The method name used by the media scanner and mtp to tell the media provider to
135 * rescan and reclassify that have become unhidden because of renaming folders or
136 * removing nomedia files
137 * @hide
138 */
139 public static final String UNHIDE_CALL = "unhide";
140
141 /**
Sean Stout87313542017-09-08 11:21:16 -0700142 * The method name used by the media scanner service to reload all localized ringtone titles due
143 * to a locale change.
144 * @hide
145 */
146 public static final String RETRANSLATE_CALL = "update_titles";
147
Jeff Sharkey643e99e2018-10-22 18:01:27 -0600148 /** {@hide} */
149 public static final String GET_DOCUMENT_URI_CALL = "get_document_uri";
150 /** {@hide} */
151 public static final String GET_MEDIA_URI_CALL = "get_media_uri";
152
Jeff Sharkey9efa7b82018-12-07 17:15:36 -0700153 /** {@hide} */
154 public static final String GET_CONTRIBUTED_MEDIA_CALL = "get_contributed_media";
155 /** {@hide} */
156 public static final String DELETE_CONTRIBUTED_MEDIA_CALL = "delete_contributed_media";
157
Sean Stout87313542017-09-08 11:21:16 -0700158 /**
Marco Nelissenac259f12012-02-07 07:54:39 -0800159 * This is for internal use by the media scanner only.
160 * Name of the (optional) Uri parameter that determines whether to skip deleting
161 * the file pointed to by the _data column, when deleting the database entry.
162 * The only appropriate value for this parameter is "false", in which case the
163 * delete will be skipped. Note especially that setting this to true, or omitting
164 * the parameter altogether, will perform the default action, which is different
165 * for different types of media.
166 * @hide
167 */
168 public static final String PARAM_DELETE_DATA = "deletedata";
169
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600170 /** {@hide} */
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600171 public static final String PARAM_INCLUDE_PENDING = "includePending";
172 /** {@hide} */
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700173 public static final String PARAM_INCLUDE_TRASHED = "includeTrashed";
174 /** {@hide} */
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600175 public static final String PARAM_PROGRESS = "progress";
Jeff Sharkeycb394992018-12-01 18:26:43 -0700176 /** {@hide} */
177 public static final String PARAM_REQUIRE_ORIGINAL = "requireOriginal";
Sudheer Shankae93db512019-01-11 16:05:28 -0800178 /** {@hide} */
179 public static final String PARAM_LIMIT = "limit";
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600180
Marco Nelissenac259f12012-02-07 07:54:39 -0800181 /**
Daniel Sandleredcdbb62010-02-18 16:00:43 -0500182 * Activity Action: Launch a music player.
183 * The activity should be able to play, browse, or manipulate music files stored on the device.
Jeff Brown6651a632011-11-28 12:59:11 -0800184 *
185 * @deprecated Use {@link android.content.Intent#CATEGORY_APP_MUSIC} instead.
Daniel Sandleredcdbb62010-02-18 16:00:43 -0500186 */
Jeff Brown6651a632011-11-28 12:59:11 -0800187 @Deprecated
Daniel Sandleredcdbb62010-02-18 16:00:43 -0500188 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
189 public static final String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
190
191 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 * Activity Action: Perform a search for media.
193 * Contains at least the {@link android.app.SearchManager#QUERY} extra.
194 * May also contain any combination of the following extras:
195 * EXTRA_MEDIA_ARTIST, EXTRA_MEDIA_ALBUM, EXTRA_MEDIA_TITLE, EXTRA_MEDIA_FOCUS
196 *
197 * @see android.provider.MediaStore#EXTRA_MEDIA_ARTIST
198 * @see android.provider.MediaStore#EXTRA_MEDIA_ALBUM
199 * @see android.provider.MediaStore#EXTRA_MEDIA_TITLE
200 * @see android.provider.MediaStore#EXTRA_MEDIA_FOCUS
201 */
202 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
203 public static final String INTENT_ACTION_MEDIA_SEARCH = "android.intent.action.MEDIA_SEARCH";
204
205 /**
Mike LeBeau2fe6fd02010-09-08 19:10:17 -0400206 * An intent to perform a search for music media and automatically play content from the
207 * result when possible. This can be fired, for example, by the result of a voice recognition
208 * command to listen to music.
Ricardo Cerveraa3b13842014-04-01 17:38:08 -0700209 * <p>This intent always includes the {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS}
210 * and {@link android.app.SearchManager#QUERY} extras. The
211 * {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS} extra determines the search mode, and
212 * the value of the {@link android.app.SearchManager#QUERY} extra depends on the search mode.
213 * For more information about the search modes for this intent, see
214 * <a href="{@docRoot}guide/components/intents-common.html#PlaySearch">Play music based
215 * on a search query</a> in <a href="{@docRoot}guide/components/intents-common.html">Common
216 * Intents</a>.</p>
217 *
218 * <p>This intent makes the most sense for apps that can support large-scale search of music,
219 * such as services connected to an online database of music which can be streamed and played
220 * on the device.</p>
Mike LeBeau2fe6fd02010-09-08 19:10:17 -0400221 */
Jeff Sharkey32cd2fb2013-10-02 10:11:22 -0700222 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Mike LeBeau2fe6fd02010-09-08 19:10:17 -0400223 public static final String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH =
224 "android.media.action.MEDIA_PLAY_FROM_SEARCH";
Wu-cheng Lif8832052012-08-20 18:30:00 +0800225
Mike LeBeau2fe6fd02010-09-08 19:10:17 -0400226 /**
Florian Uunkb1ac72b2012-09-21 12:16:16 +0100227 * An intent to perform a search for readable media and automatically play content from the
228 * result when possible. This can be fired, for example, by the result of a voice recognition
229 * command to read a book or magazine.
230 * <p>
231 * Contains the {@link android.app.SearchManager#QUERY} extra, which is a string that can
232 * contain any type of unstructured text search, like the name of a book or magazine, an author
233 * a genre, a publisher, or any combination of these.
234 * <p>
235 * Because this intent includes an open-ended unstructured search string, it makes the most
236 * sense for apps that can support large-scale search of text media, such as services connected
237 * to an online database of books and/or magazines which can be read on the device.
238 */
Jeff Sharkey32cd2fb2013-10-02 10:11:22 -0700239 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Florian Uunkb1ac72b2012-09-21 12:16:16 +0100240 public static final String INTENT_ACTION_TEXT_OPEN_FROM_SEARCH =
241 "android.media.action.TEXT_OPEN_FROM_SEARCH";
242
243 /**
244 * An intent to perform a search for video media and automatically play content from the
245 * result when possible. This can be fired, for example, by the result of a voice recognition
246 * command to play movies.
247 * <p>
248 * Contains the {@link android.app.SearchManager#QUERY} extra, which is a string that can
249 * contain any type of unstructured video search, like the name of a movie, one or more actors,
250 * a genre, or any combination of these.
251 * <p>
252 * Because this intent includes an open-ended unstructured search string, it makes the most
253 * sense for apps that can support large-scale search of video, such as services connected to an
254 * online database of videos which can be streamed and played on the device.
255 */
Jeff Sharkey32cd2fb2013-10-02 10:11:22 -0700256 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Florian Uunkb1ac72b2012-09-21 12:16:16 +0100257 public static final String INTENT_ACTION_VIDEO_PLAY_FROM_SEARCH =
258 "android.media.action.VIDEO_PLAY_FROM_SEARCH";
259
260 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 * The name of the Intent-extra used to define the artist
262 */
263 public static final String EXTRA_MEDIA_ARTIST = "android.intent.extra.artist";
264 /**
265 * The name of the Intent-extra used to define the album
266 */
267 public static final String EXTRA_MEDIA_ALBUM = "android.intent.extra.album";
268 /**
269 * The name of the Intent-extra used to define the song title
270 */
271 public static final String EXTRA_MEDIA_TITLE = "android.intent.extra.title";
272 /**
Matt Caseybd7bcf02014-02-05 15:51:39 -0800273 * The name of the Intent-extra used to define the genre.
274 */
275 public static final String EXTRA_MEDIA_GENRE = "android.intent.extra.genre";
276 /**
Matt Casey1dbf1f82014-03-26 17:09:56 -0700277 * The name of the Intent-extra used to define the playlist.
278 */
279 public static final String EXTRA_MEDIA_PLAYLIST = "android.intent.extra.playlist";
280 /**
Matt Caseybd7bcf02014-02-05 15:51:39 -0800281 * The name of the Intent-extra used to define the radio channel.
282 */
283 public static final String EXTRA_MEDIA_RADIO_CHANNEL = "android.intent.extra.radio_channel";
284 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285 * The name of the Intent-extra used to define the search focus. The search focus
286 * indicates whether the search should be for things related to the artist, album
287 * or song that is identified by the other extras.
288 */
289 public static final String EXTRA_MEDIA_FOCUS = "android.intent.extra.focus";
290
291 /**
292 * The name of the Intent-extra used to control the orientation of a ViewImage or a MovieView.
293 * This is an int property that overrides the activity's requestedOrientation.
Aurimas Liutikase701dc12018-06-01 16:04:37 -0700294 * @see android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 */
296 public static final String EXTRA_SCREEN_ORIENTATION = "android.intent.extra.screenOrientation";
297
298 /**
299 * The name of an Intent-extra used to control the UI of a ViewImage.
300 * This is a boolean property that overrides the activity's default fullscreen state.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 */
302 public static final String EXTRA_FULL_SCREEN = "android.intent.extra.fullScreen";
303
304 /**
305 * The name of an Intent-extra used to control the UI of a ViewImage.
306 * This is a boolean property that specifies whether or not to show action icons.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 */
308 public static final String EXTRA_SHOW_ACTION_ICONS = "android.intent.extra.showActionIcons";
309
310 /**
311 * The name of the Intent-extra used to control the onCompletion behavior of a MovieView.
312 * This is a boolean property that specifies whether or not to finish the MovieView activity
313 * when the movie completes playing. The default value is true, which means to automatically
314 * exit the movie player activity when the movie completes playing.
315 */
316 public static final String EXTRA_FINISH_ON_COMPLETION = "android.intent.extra.finishOnCompletion";
317
318 /**
319 * The name of the Intent action used to launch a camera in still image mode.
320 */
Jeff Sharkey32cd2fb2013-10-02 10:11:22 -0700321 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
323
324 /**
Jorim Jaggid9449862015-05-29 14:49:08 -0700325 * Name under which an activity handling {@link #INTENT_ACTION_STILL_IMAGE_CAMERA} or
326 * {@link #INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE} publishes the service name for its prewarm
327 * service.
Jorim Jaggia86790b2015-04-02 16:32:29 -0700328 * <p>
Jorim Jaggid9449862015-05-29 14:49:08 -0700329 * This meta-data should reference the fully qualified class name of the prewarm service
330 * extending {@link CameraPrewarmService}.
Jorim Jaggia86790b2015-04-02 16:32:29 -0700331 * <p>
Jorim Jaggid9449862015-05-29 14:49:08 -0700332 * The prewarm service will get bound and receive a prewarm signal
333 * {@link CameraPrewarmService#onPrewarm()} when a camera launch intent fire might be imminent.
334 * An application implementing a prewarm service should do the absolute minimum amount of work
335 * to initialize the camera in order to reduce startup time in likely case that shortly after a
336 * camera launch intent would be sent.
Jorim Jaggia86790b2015-04-02 16:32:29 -0700337 */
Jorim Jaggid9449862015-05-29 14:49:08 -0700338 public static final String META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE =
339 "android.media.still_image_camera_preview_service";
Jorim Jaggia86790b2015-04-02 16:32:29 -0700340
341 /**
Wu-cheng Lif8832052012-08-20 18:30:00 +0800342 * The name of the Intent action used to launch a camera in still image mode
343 * for use when the device is secured (e.g. with a pin, password, pattern,
344 * or face unlock). Applications responding to this intent must not expose
345 * any personal content like existing photos or videos on the device. The
346 * applications should be careful not to share any photo or video with other
347 * applications or internet. The activity should use {@link
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -0600348 * Activity#setShowWhenLocked} to display
Wu-cheng Lif8832052012-08-20 18:30:00 +0800349 * on top of the lock screen while secured. There is no activity stack when
350 * this flag is used, so launching more than one activity is strongly
351 * discouraged.
Wu-cheng Lif8832052012-08-20 18:30:00 +0800352 */
Jeff Sharkey32cd2fb2013-10-02 10:11:22 -0700353 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Wu-cheng Lif8832052012-08-20 18:30:00 +0800354 public static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE =
355 "android.media.action.STILL_IMAGE_CAMERA_SECURE";
356
357 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 * The name of the Intent action used to launch a camera in video mode.
359 */
Jeff Sharkey32cd2fb2013-10-02 10:11:22 -0700360 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 public static final String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
362
363 /**
364 * Standard Intent action that can be sent to have the camera application
365 * capture an image and return it.
366 * <p>
367 * The caller may pass an extra EXTRA_OUTPUT to control where this image will be written.
368 * If the EXTRA_OUTPUT is not present, then a small sized image is returned as a Bitmap
369 * object in the extra field. This is useful for applications that only need a small image.
370 * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri
371 * value of EXTRA_OUTPUT.
Dianne Hackborn955d8d62014-10-07 20:17:19 -0700372 * As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this uri can also be supplied through
Nicolas Prevotd1c99b12014-07-04 16:56:17 +0100373 * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must
374 * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
375 * If you don't set a ClipData, it will be copied there for you when calling
376 * {@link Context#startActivity(Intent)}.
Svetoslav7008b512015-06-24 18:47:07 -0700377 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -0700378 * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#M M} and above
Svetoslav7008b512015-06-24 18:47:07 -0700379 * and declares as using the {@link android.Manifest.permission#CAMERA} permission which
Philip P. Moltmannf8173ca2016-04-12 15:11:23 -0700380 * is not granted, then attempting to use this action will result in a {@link
Svetoslav7008b512015-06-24 18:47:07 -0700381 * java.lang.SecurityException}.
382 *
383 * @see #EXTRA_OUTPUT
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 */
Jeff Sharkey32cd2fb2013-10-02 10:11:22 -0700385 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
387
388 /**
Wu-cheng Li37959ef2012-09-21 14:40:26 +0800389 * Intent action that can be sent to have the camera application capture an image and return
390 * it when the device is secured (e.g. with a pin, password, pattern, or face unlock).
391 * Applications responding to this intent must not expose any personal content like existing
392 * photos or videos on the device. The applications should be careful not to share any photo
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -0600393 * or video with other applications or Internet. The activity should use {@link
394 * Activity#setShowWhenLocked} to display on top of the
Wu-cheng Li37959ef2012-09-21 14:40:26 +0800395 * lock screen while secured. There is no activity stack when this flag is used, so
396 * launching more than one activity is strongly discouraged.
397 * <p>
398 * The caller may pass an extra EXTRA_OUTPUT to control where this image will be written.
399 * If the EXTRA_OUTPUT is not present, then a small sized image is returned as a Bitmap
400 * object in the extra field. This is useful for applications that only need a small image.
401 * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri
402 * value of EXTRA_OUTPUT.
Dianne Hackborn955d8d62014-10-07 20:17:19 -0700403 * As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this uri can also be supplied through
Nicolas Prevotd1c99b12014-07-04 16:56:17 +0100404 * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must
405 * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
406 * If you don't set a ClipData, it will be copied there for you when calling
407 * {@link Context#startActivity(Intent)}.
Wu-cheng Li37959ef2012-09-21 14:40:26 +0800408 *
409 * @see #ACTION_IMAGE_CAPTURE
410 * @see #EXTRA_OUTPUT
Wu-cheng Li37959ef2012-09-21 14:40:26 +0800411 */
Jeff Sharkey32cd2fb2013-10-02 10:11:22 -0700412 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Wu-cheng Li37959ef2012-09-21 14:40:26 +0800413 public static final String ACTION_IMAGE_CAPTURE_SECURE =
414 "android.media.action.IMAGE_CAPTURE_SECURE";
415
416 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 * Standard Intent action that can be sent to have the camera application
Ken Wakasaf76a50c2012-03-09 19:56:35 +0900418 * capture a video and return it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 * <p>
420 * The caller may pass in an extra EXTRA_VIDEO_QUALITY to control the video quality.
421 * <p>
422 * The caller may pass in an extra EXTRA_OUTPUT to control
423 * where the video is written. If EXTRA_OUTPUT is not present the video will be
424 * written to the standard location for videos, and the Uri of that location will be
425 * returned in the data field of the Uri.
Dianne Hackborn955d8d62014-10-07 20:17:19 -0700426 * As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this uri can also be supplied through
Nicolas Prevotd1c99b12014-07-04 16:56:17 +0100427 * {@link android.content.Intent#setClipData(ClipData)}. If using this approach, you still must
428 * supply the uri through the EXTRA_OUTPUT field for compatibility with old applications.
429 * If you don't set a ClipData, it will be copied there for you when calling
430 * {@link Context#startActivity(Intent)}.
Svetoslav7008b512015-06-24 18:47:07 -0700431 *
Dianne Hackborn0e3de6c2015-07-29 15:20:21 -0700432 * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#M M} and above
Svetoslav7008b512015-06-24 18:47:07 -0700433 * and declares as using the {@link android.Manifest.permission#CAMERA} permission which
434 * is not granted, then atempting to use this action will result in a {@link
435 * java.lang.SecurityException}.
436 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 * @see #EXTRA_OUTPUT
Wu-cheng Lie7bc7462011-03-16 17:18:58 +0800438 * @see #EXTRA_VIDEO_QUALITY
439 * @see #EXTRA_SIZE_LIMIT
440 * @see #EXTRA_DURATION_LIMIT
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 */
Jeff Sharkey32cd2fb2013-10-02 10:11:22 -0700442 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 public final static String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
444
445 /**
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -0600446 * Standard action that can be sent to review the given media file.
447 * <p>
448 * The launched application is expected to provide a large-scale view of the
449 * given media file, while allowing the user to quickly access other
450 * recently captured media files.
451 * <p>
452 * Input: {@link Intent#getData} is URI of the primary media item to
453 * initially display.
454 *
455 * @see #ACTION_REVIEW_SECURE
456 * @see #EXTRA_BRIGHTNESS
457 */
458 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
459 public final static String ACTION_REVIEW = "android.provider.action.REVIEW";
460
461 /**
462 * Standard action that can be sent to review the given media file when the
463 * device is secured (e.g. with a pin, password, pattern, or face unlock).
464 * The applications should be careful not to share any media with other
465 * applications or Internet. The activity should use
466 * {@link Activity#setShowWhenLocked} to display on top of the lock screen
467 * while secured. There is no activity stack when this flag is used, so
468 * launching more than one activity is strongly discouraged.
469 * <p>
470 * The launched application is expected to provide a large-scale view of the
471 * given primary media file, while only allowing the user to quickly access
472 * other media from an explicit secondary list.
473 * <p>
474 * Input: {@link Intent#getData} is URI of the primary media item to
475 * initially display. {@link Intent#getClipData} is the limited list of
476 * secondary media items that the user is allowed to review. If
477 * {@link Intent#getClipData} is undefined, then no other media access
478 * should be allowed.
479 *
480 * @see #EXTRA_BRIGHTNESS
481 */
482 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
483 public final static String ACTION_REVIEW_SECURE = "android.provider.action.REVIEW_SECURE";
484
485 /**
486 * When defined, the launched application is requested to set the given
487 * brightness value via
488 * {@link android.view.WindowManager.LayoutParams#screenBrightness} to help
489 * ensure a smooth transition when launching {@link #ACTION_REVIEW} or
490 * {@link #ACTION_REVIEW_SECURE} intents.
491 */
492 public final static String EXTRA_BRIGHTNESS = "android.provider.extra.BRIGHTNESS";
493
494 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 * The name of the Intent-extra used to control the quality of a recorded video. This is an
496 * integer property. Currently value 0 means low quality, suitable for MMS messages, and
497 * value 1 means high quality. In the future other quality levels may be added.
498 */
499 public final static String EXTRA_VIDEO_QUALITY = "android.intent.extra.videoQuality";
500
501 /**
502 * Specify the maximum allowed size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 */
504 public final static String EXTRA_SIZE_LIMIT = "android.intent.extra.sizeLimit";
505
506 /**
Chih-Chung Changeb0098d2009-08-25 12:59:54 +0800507 * Specify the maximum allowed recording duration in seconds.
Chih-Chung Changeb0098d2009-08-25 12:59:54 +0800508 */
509 public final static String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
510
511 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 * The name of the Intent-extra used to indicate a content resolver Uri to be used to
513 * store the requested image or video.
514 */
515 public final static String EXTRA_OUTPUT = "output";
516
517 /**
Marco Nelissened297a82010-01-04 13:24:31 -0800518 * The string that is used when a media attribute is not known. For example,
519 * if an audio file does not have any meta data, the artist and album columns
520 * will be set to this value.
Marco Nelissened297a82010-01-04 13:24:31 -0800521 */
522 public static final String UNKNOWN_STRING = "<unknown>";
523
524 /**
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600525 * Update the given {@link Uri} to also include any pending media items from
526 * calls such as
527 * {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}.
528 * By default no pending items are returned.
529 *
530 * @see MediaColumns#IS_PENDING
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700531 * @see MediaStore#setIncludePending(Uri)
532 * @see MediaStore#createPending(Context, PendingParams)
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600533 */
534 public static @NonNull Uri setIncludePending(@NonNull Uri uri) {
Sudheer Shankae93db512019-01-11 16:05:28 -0800535 return setIncludePending(uri.buildUpon()).build();
536 }
537
538 /** @hide */
539 public static @NonNull Uri.Builder setIncludePending(@NonNull Uri.Builder uriBuilder) {
540 return uriBuilder.appendQueryParameter(PARAM_INCLUDE_PENDING, "1");
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600541 }
542
543 /**
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700544 * Update the given {@link Uri} to also include any trashed media items from
545 * calls such as
546 * {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}.
547 * By default no trashed items are returned.
548 *
549 * @see MediaColumns#IS_TRASHED
550 * @see MediaStore#setIncludeTrashed(Uri)
551 * @see MediaStore#trash(Context, Uri)
552 * @see MediaStore#untrash(Context, Uri)
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -0700553 * @removed
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700554 */
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -0700555 @Deprecated
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700556 public static @NonNull Uri setIncludeTrashed(@NonNull Uri uri) {
557 return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_TRASHED, "1").build();
558 }
559
560 /**
Jeff Sharkeycb394992018-12-01 18:26:43 -0700561 * Update the given {@link Uri} to indicate that the caller requires the
562 * original file contents when calling
563 * {@link ContentResolver#openFileDescriptor(Uri, String)}.
564 * <p>
565 * This can be useful when the caller wants to ensure they're backing up the
566 * exact bytes of the underlying media, without any Exif redaction being
567 * performed.
568 * <p>
569 * If the original file contents cannot be provided, a
570 * {@link UnsupportedOperationException} will be thrown when the returned
571 * {@link Uri} is used, such as when the caller doesn't hold
572 * {@link android.Manifest.permission#ACCESS_MEDIA_LOCATION}.
573 */
574 public static @NonNull Uri setRequireOriginal(@NonNull Uri uri) {
575 return uri.buildUpon().appendQueryParameter(PARAM_REQUIRE_ORIGINAL, "1").build();
576 }
577
578 /**
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600579 * Create a new pending media item using the given parameters. Pending items
580 * are expected to have a short lifetime, and owners should either
581 * {@link PendingSession#publish()} or {@link PendingSession#abandon()} a
582 * pending item within a few hours after first creating it.
583 *
584 * @return token which can be passed to {@link #openPending(Context, Uri)}
585 * to work with this pending item.
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700586 * @see MediaColumns#IS_PENDING
587 * @see MediaStore#setIncludePending(Uri)
588 * @see MediaStore#createPending(Context, PendingParams)
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600589 */
590 public static @NonNull Uri createPending(@NonNull Context context,
591 @NonNull PendingParams params) {
Jeff Sharkeyd8dc4bc2019-02-08 14:03:35 -0700592 return context.getContentResolver().insert(params.insertUri, params.insertValues);
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600593 }
594
595 /**
596 * Open a pending media item to make progress on it. You can open a pending
597 * item multiple times before finally calling either
598 * {@link PendingSession#publish()} or {@link PendingSession#abandon()}.
599 *
600 * @param uri token which was previously returned from
601 * {@link #createPending(Context, PendingParams)}.
602 */
603 public static @NonNull PendingSession openPending(@NonNull Context context, @NonNull Uri uri) {
604 return new PendingSession(context, uri);
605 }
606
607 /**
608 * Parameters that describe a pending media item.
609 */
610 public static class PendingParams {
611 /** {@hide} */
612 public final Uri insertUri;
613 /** {@hide} */
614 public final ContentValues insertValues;
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600615
616 /**
617 * Create parameters that describe a pending media item.
618 *
619 * @param insertUri the {@code content://} Uri where this pending item
620 * should be inserted when finally published. For example, to
621 * publish an image, use
622 * {@link MediaStore.Images.Media#getContentUri(String)}.
623 */
624 public PendingParams(@NonNull Uri insertUri, @NonNull String displayName,
625 @NonNull String mimeType) {
626 this.insertUri = Objects.requireNonNull(insertUri);
627 final long now = System.currentTimeMillis() / 1000;
628 this.insertValues = new ContentValues();
629 this.insertValues.put(MediaColumns.DISPLAY_NAME, Objects.requireNonNull(displayName));
630 this.insertValues.put(MediaColumns.MIME_TYPE, Objects.requireNonNull(mimeType));
631 this.insertValues.put(MediaColumns.DATE_ADDED, now);
632 this.insertValues.put(MediaColumns.DATE_MODIFIED, now);
633 this.insertValues.put(MediaColumns.IS_PENDING, 1);
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700634 this.insertValues.put(MediaColumns.DATE_EXPIRES,
635 (System.currentTimeMillis() + DateUtils.DAY_IN_MILLIS) / 1000);
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600636 }
637
638 /**
639 * Optionally set the primary directory under which this pending item
640 * should be persisted. Only specific well-defined directories from
641 * {@link Environment} are allowed based on the media type being
642 * inserted.
643 * <p>
644 * For example, when creating pending {@link MediaStore.Images.Media}
645 * items, only {@link Environment#DIRECTORY_PICTURES} or
646 * {@link Environment#DIRECTORY_DCIM} are allowed.
647 * <p>
648 * You may leave this value undefined to store the media in a default
649 * location. For example, when this value is left undefined, pending
650 * {@link MediaStore.Audio.Media} items are stored under
651 * {@link Environment#DIRECTORY_MUSIC}.
Jeff Sharkeyc4597792019-01-30 15:14:19 -0700652 *
653 * @see MediaColumns#PRIMARY_DIRECTORY
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600654 */
655 public void setPrimaryDirectory(@Nullable String primaryDirectory) {
Jeff Sharkeyd8dc4bc2019-02-08 14:03:35 -0700656 if (primaryDirectory == null) {
657 this.insertValues.remove(MediaColumns.PRIMARY_DIRECTORY);
658 } else {
659 this.insertValues.put(MediaColumns.PRIMARY_DIRECTORY, primaryDirectory);
660 }
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600661 }
662
663 /**
664 * Optionally set the secondary directory under which this pending item
665 * should be persisted. Any valid directory name is allowed.
666 * <p>
667 * You may leave this value undefined to store the media as a direct
668 * descendant of the {@link #setPrimaryDirectory(String)} location.
Jeff Sharkeyc4597792019-01-30 15:14:19 -0700669 *
670 * @see MediaColumns#SECONDARY_DIRECTORY
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600671 */
672 public void setSecondaryDirectory(@Nullable String secondaryDirectory) {
Jeff Sharkeyd8dc4bc2019-02-08 14:03:35 -0700673 if (secondaryDirectory == null) {
674 this.insertValues.remove(MediaColumns.SECONDARY_DIRECTORY);
675 } else {
676 this.insertValues.put(MediaColumns.SECONDARY_DIRECTORY, secondaryDirectory);
677 }
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600678 }
Sudheer Shanka9b98edb2018-11-15 20:29:03 -0800679
680 /**
681 * Optionally set the Uri from where the file has been downloaded. This is used
682 * for files being added to {@link Downloads} table.
683 *
684 * @see DownloadColumns#DOWNLOAD_URI
685 */
686 public void setDownloadUri(@Nullable Uri downloadUri) {
687 if (downloadUri == null) {
688 this.insertValues.remove(DownloadColumns.DOWNLOAD_URI);
689 } else {
690 this.insertValues.put(DownloadColumns.DOWNLOAD_URI, downloadUri.toString());
691 }
692 }
693
694 /**
695 * Optionally set the Uri indicating HTTP referer of the file. This is used for
696 * files being added to {@link Downloads} table.
697 *
698 * @see DownloadColumns#REFERER_URI
699 */
700 public void setRefererUri(@Nullable Uri refererUri) {
701 if (refererUri == null) {
702 this.insertValues.remove(DownloadColumns.REFERER_URI);
703 } else {
704 this.insertValues.put(DownloadColumns.REFERER_URI, refererUri.toString());
705 }
706 }
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600707 }
708
709 /**
710 * Session actively working on a pending media item. Pending items are
711 * expected to have a short lifetime, and owners should either
712 * {@link PendingSession#publish()} or {@link PendingSession#abandon()} a
713 * pending item within a few hours after first creating it.
714 */
715 public static class PendingSession implements AutoCloseable {
716 /** {@hide} */
717 private final Context mContext;
718 /** {@hide} */
719 private final Uri mUri;
720
721 /** {@hide} */
722 public PendingSession(Context context, Uri uri) {
723 mContext = Objects.requireNonNull(context);
724 mUri = Objects.requireNonNull(uri);
725 }
726
727 /**
728 * Open the underlying file representing this media item. When a media
729 * item is successfully completed, you should
730 * {@link ParcelFileDescriptor#close()} and then {@link #publish()} it.
731 *
732 * @see #notifyProgress(int)
733 */
734 public @NonNull ParcelFileDescriptor open() throws FileNotFoundException {
735 return mContext.getContentResolver().openFileDescriptor(mUri, "rw");
736 }
737
738 /**
739 * Open the underlying file representing this media item. When a media
740 * item is successfully completed, you should
741 * {@link OutputStream#close()} and then {@link #publish()} it.
742 *
743 * @see #notifyProgress(int)
744 */
745 public @NonNull OutputStream openOutputStream() throws FileNotFoundException {
746 return mContext.getContentResolver().openOutputStream(mUri);
747 }
748
749 /**
750 * Notify of current progress on this pending media item. Gallery
751 * applications may choose to surface progress information of this
752 * pending item.
753 *
754 * @param progress a percentage between 0 and 100.
755 */
756 public void notifyProgress(@IntRange(from = 0, to = 100) int progress) {
757 final Uri withProgress = mUri.buildUpon()
758 .appendQueryParameter(PARAM_PROGRESS, Integer.toString(progress)).build();
759 mContext.getContentResolver().notifyChange(withProgress, null, 0);
760 }
761
762 /**
763 * When this media item is successfully completed, call this method to
764 * publish and make the final item visible to the user.
765 *
766 * @return the final {@code content://} Uri representing the newly
767 * published media.
768 */
769 public @NonNull Uri publish() {
770 final ContentValues values = new ContentValues();
771 values.put(MediaColumns.IS_PENDING, 0);
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700772 values.putNull(MediaColumns.DATE_EXPIRES);
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600773 mContext.getContentResolver().update(mUri, values, null, null);
774 return mUri;
775 }
776
777 /**
778 * When this media item has failed to be completed, call this method to
779 * destroy the pending item record and any data related to it.
780 */
781 public void abandon() {
782 mContext.getContentResolver().delete(mUri, null, null);
783 }
784
785 @Override
786 public void close() {
787 // No resources to close, but at least we can inform people that no
788 // progress is being actively made.
789 notifyProgress(-1);
790 }
791 }
792
793 /**
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700794 * Mark the given item as being "trashed", meaning it should be deleted at
795 * some point in the future. This is a more gentle operation than simply
796 * calling {@link ContentResolver#delete(Uri, String, String[])}, which
797 * would take effect immediately.
798 * <p>
799 * This method preserves trashed items for at least 48 hours before erasing
800 * them, giving the user a chance to untrash the item.
801 *
802 * @see MediaColumns#IS_TRASHED
803 * @see MediaStore#setIncludeTrashed(Uri)
804 * @see MediaStore#trash(Context, Uri)
805 * @see MediaStore#untrash(Context, Uri)
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -0700806 * @removed
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700807 */
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -0700808 @Deprecated
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700809 public static void trash(@NonNull Context context, @NonNull Uri uri) {
810 trash(context, uri, 48 * DateUtils.HOUR_IN_MILLIS);
811 }
812
813 /**
814 * Mark the given item as being "trashed", meaning it should be deleted at
815 * some point in the future. This is a more gentle operation than simply
816 * calling {@link ContentResolver#delete(Uri, String, String[])}, which
817 * would take effect immediately.
818 * <p>
819 * This method preserves trashed items for at least the given timeout before
820 * erasing them, giving the user a chance to untrash the item.
821 *
822 * @see MediaColumns#IS_TRASHED
823 * @see MediaStore#setIncludeTrashed(Uri)
824 * @see MediaStore#trash(Context, Uri)
825 * @see MediaStore#untrash(Context, Uri)
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -0700826 * @removed
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700827 */
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -0700828 @Deprecated
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700829 public static void trash(@NonNull Context context, @NonNull Uri uri,
830 @DurationMillisLong long timeoutMillis) {
831 if (timeoutMillis < 0) {
832 throw new IllegalArgumentException();
833 }
834
835 final ContentValues values = new ContentValues();
836 values.put(MediaColumns.IS_TRASHED, 1);
837 values.put(MediaColumns.DATE_EXPIRES,
838 (System.currentTimeMillis() + timeoutMillis) / 1000);
839 context.getContentResolver().update(uri, values, null, null);
840 }
841
842 /**
843 * Mark the given item as being "untrashed", meaning it should no longer be
844 * deleted as previously requested through {@link #trash(Context, Uri)}.
845 *
846 * @see MediaColumns#IS_TRASHED
847 * @see MediaStore#setIncludeTrashed(Uri)
848 * @see MediaStore#trash(Context, Uri)
849 * @see MediaStore#untrash(Context, Uri)
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -0700850 * @removed
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700851 */
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -0700852 @Deprecated
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700853 public static void untrash(@NonNull Context context, @NonNull Uri uri) {
854 final ContentValues values = new ContentValues();
855 values.put(MediaColumns.IS_TRASHED, 0);
856 values.putNull(MediaColumns.DATE_EXPIRES);
857 context.getContentResolver().update(uri, values, null, null);
858 }
859
860 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -0700861 * Common media metadata columns.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862 */
Ray Chen00c575a2009-08-28 14:12:15 -0700863 public interface MediaColumns extends BaseColumns {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -0700865 * Path to the media item on disk.
Jeff Sharkey60cfad82016-01-05 17:30:57 -0700866 * <p>
867 * Note that apps may not have filesystem permissions to directly access
868 * this path. Instead of trying to open this path directly, apps should
869 * use {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
870 * access.
Jeff Sharkey52827962018-10-18 14:44:41 -0600871 *
872 * @deprecated Apps may not have filesystem permissions to directly
873 * access this path. Instead of trying to open this path
874 * directly, apps should use
875 * {@link ContentResolver#openFileDescriptor(Uri, String)}
876 * to gain access. This value will always be {@code NULL}
877 * for apps targeting
878 * {@link android.os.Build.VERSION_CODES#Q} or higher.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 */
Jeff Sharkey52827962018-10-18 14:44:41 -0600880 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -0700881 @Column(Cursor.FIELD_TYPE_STRING)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882 public static final String DATA = "_data";
883
884 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -0700885 * Hash of the media item on disk.
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -0600886 * <p>
887 * Contains a 20-byte binary blob which is the SHA-1 hash of the file as
888 * persisted on disk. For performance reasons, the hash may not be
889 * immediately available, in which case a {@code NULL} value will be
890 * returned. If the underlying file is modified, this value will be
891 * cleared and recalculated.
892 * <p>
893 * If you require the hash of a specific item, you can call
894 * {@link ContentResolver#canonicalize(Uri)}, which will block until the
895 * hash is calculated.
Jeff Sharkey9c41bda2019-02-14 15:29:37 -0700896 *
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -0700897 * @removed
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -0600898 */
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -0700899 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -0700900 @Column(value = Cursor.FIELD_TYPE_BLOB, readOnly = true)
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -0600901 public static final String HASH = "_hash";
902
903 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -0700904 * The size of the media item.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -0700906 @BytesLong
Jeff Sharkey9c41bda2019-02-14 15:29:37 -0700907 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 public static final String SIZE = "_size";
909
910 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -0700911 * The display name of the media item.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -0700913 @Column(Cursor.FIELD_TYPE_STRING)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 public static final String DISPLAY_NAME = "_display_name";
915
916 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -0700917 * The title of the media item.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -0700919 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 public static final String TITLE = "title";
921
922 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -0700923 * The time the media item was first added.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -0700925 @CurrentTimeSecondsLong
Jeff Sharkey9c41bda2019-02-14 15:29:37 -0700926 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 public static final String DATE_ADDED = "date_added";
928
929 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -0700930 * The time the media item was last modified.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -0700932 @CurrentTimeSecondsLong
Jeff Sharkey9c41bda2019-02-14 15:29:37 -0700933 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 public static final String DATE_MODIFIED = "date_modified";
935
936 /**
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -0700937 * The MIME type of the media item.
938 * <p>
939 * This is typically defined based on the file extension of the media
940 * item. However, it may be the value of the {@code format} attribute
941 * defined by the <em>Dublin Core Media Initiative</em> standard,
942 * extracted from any XMP metadata contained within this media item.
943 * <p class="note">
944 * Note: the {@code format} attribute may be ignored if the top-level
945 * MIME type disagrees with the file extension. For example, it's
946 * reasonable for an {@code image/jpeg} file to declare a {@code format}
947 * of {@code image/vnd.google.panorama360+jpg}, but declaring a
948 * {@code format} of {@code audio/ogg} would be ignored.
949 * <p>
950 * This is a read-only column that is automatically computed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -0700952 @Column(Cursor.FIELD_TYPE_STRING)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 public static final String MIME_TYPE = "mime_type";
Mike Lockwoodd815f792010-07-12 08:49:01 -0400954
955 /**
Mike Lockwoodcbaea352010-07-17 08:34:17 -0400956 * The MTP object handle of a newly transfered file.
957 * Used to pass the new file's object handle through the media scanner
958 * from MTP to the media provider
959 * For internal use only by MTP, media scanner and media provider.
Mike Lockwoodcbaea352010-07-17 08:34:17 -0400960 * @hide
961 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -0700962 @Deprecated
963 // @Column(Cursor.FIELD_TYPE_INTEGER)
Mike Lockwoodcbaea352010-07-17 08:34:17 -0400964 public static final String MEDIA_SCANNER_NEW_OBJECT_ID = "media_scanner_new_object_id";
Gloria Wang82428a82011-06-27 11:09:00 -0700965
966 /**
967 * Non-zero if the media file is drm-protected
Gloria Wang82428a82011-06-27 11:09:00 -0700968 * @hide
969 */
Mathew Inwood6750f2e2018-08-10 09:29:25 +0100970 @UnsupportedAppUsage
Jeff Sharkey9c41bda2019-02-14 15:29:37 -0700971 @Deprecated
972 @Column(Cursor.FIELD_TYPE_INTEGER)
Gloria Wang82428a82011-06-27 11:09:00 -0700973 public static final String IS_DRM = "is_drm";
974
Chih-Chung Change1bf8ef2011-09-20 20:37:21 +0800975 /**
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600976 * Flag indicating if a media item is pending, and still being inserted
977 * by its owner.
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600978 *
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700979 * @see MediaColumns#IS_PENDING
980 * @see MediaStore#setIncludePending(Uri)
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600981 * @see MediaStore#createPending(Context, PendingParams)
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600982 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -0700983 @Column(Cursor.FIELD_TYPE_INTEGER)
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600984 public static final String IS_PENDING = "is_pending";
985
986 /**
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700987 * Flag indicating if a media item is trashed.
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700988 *
989 * @see MediaColumns#IS_TRASHED
990 * @see MediaStore#setIncludeTrashed(Uri)
991 * @see MediaStore#trash(Context, Uri)
992 * @see MediaStore#untrash(Context, Uri)
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -0700993 * @removed
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700994 */
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -0700995 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -0700996 @Column(Cursor.FIELD_TYPE_INTEGER)
Jeff Sharkey5cc407f2019-01-04 16:09:18 -0700997 public static final String IS_TRASHED = "is_trashed";
998
999 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001000 * The time the media item should be considered expired. Typically only
1001 * meaningful in the context of {@link #IS_PENDING} or
1002 * {@link #IS_TRASHED}.
1003 *
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -07001004 * @removed
Jeff Sharkey5cc407f2019-01-04 16:09:18 -07001005 */
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -07001006 @Deprecated
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001007 @CurrentTimeSecondsLong
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001008 @Column(Cursor.FIELD_TYPE_INTEGER)
Jeff Sharkey5cc407f2019-01-04 16:09:18 -07001009 public static final String DATE_EXPIRES = "date_expires";
1010
1011 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001012 * The width of the media item, in pixels.
Chih-Chung Change1bf8ef2011-09-20 20:37:21 +08001013 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001014 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
Chih-Chung Change1bf8ef2011-09-20 20:37:21 +08001015 public static final String WIDTH = "width";
1016
1017 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001018 * The height of the media item, in pixels.
Chih-Chung Change1bf8ef2011-09-20 20:37:21 +08001019 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001020 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
Chih-Chung Change1bf8ef2011-09-20 20:37:21 +08001021 public static final String HEIGHT = "height";
Jeff Sharkey0ce83ae2018-08-06 18:55:59 -06001022
1023 /**
Jeff Sharkeyc8e49242018-11-02 14:34:44 -06001024 * Package name that contributed this media. The value may be
1025 * {@code NULL} if ownership cannot be reliably determined.
Jeff Sharkey0ce83ae2018-08-06 18:55:59 -06001026 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001027 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
Jeff Sharkey0ce83ae2018-08-06 18:55:59 -06001028 public static final String OWNER_PACKAGE_NAME = "owner_package_name";
Jeff Sharkeyc4597792019-01-30 15:14:19 -07001029
1030 /**
1031 * The primary directory name this media exists under. The value may be
1032 * {@code NULL} if the media doesn't have a primary directory name.
Jeff Sharkeyc4597792019-01-30 15:14:19 -07001033 *
1034 * @see PendingParams#setPrimaryDirectory(String)
1035 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001036 @Column(Cursor.FIELD_TYPE_STRING)
Jeff Sharkeyc4597792019-01-30 15:14:19 -07001037 public static final String PRIMARY_DIRECTORY = "primary_directory";
1038
1039 /**
1040 * The secondary directory name this media exists under. The value may
1041 * be {@code NULL} if the media doesn't have a secondary directory name.
Jeff Sharkeyc4597792019-01-30 15:14:19 -07001042 *
1043 * @see PendingParams#setSecondaryDirectory(String)
1044 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001045 @Column(Cursor.FIELD_TYPE_STRING)
Jeff Sharkeyc4597792019-01-30 15:14:19 -07001046 public static final String SECONDARY_DIRECTORY = "secondary_directory";
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -07001047
1048 /**
1049 * The "document ID" GUID as defined by the <em>XMP Media
1050 * Management</em> standard, extracted from any XMP metadata contained
1051 * within this media item. The value is {@code null} when no metadata
1052 * was found.
1053 * <p>
1054 * Each "document ID" is created once for each new resource. Different
1055 * renditions of that resource are expected to have different IDs.
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -07001056 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001057 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -07001058 public static final String DOCUMENT_ID = "document_id";
1059
1060 /**
1061 * The "instance ID" GUID as defined by the <em>XMP Media
1062 * Management</em> standard, extracted from any XMP metadata contained
1063 * within this media item. The value is {@code null} when no metadata
1064 * was found.
1065 * <p>
1066 * This "instance ID" changes with each save operation of a specific
1067 * "document ID".
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -07001068 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001069 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -07001070 public static final String INSTANCE_ID = "instance_id";
1071
1072 /**
1073 * The "original document ID" GUID as defined by the <em>XMP Media
1074 * Management</em> standard, extracted from any XMP metadata contained
1075 * within this media item.
1076 * <p>
1077 * This "original document ID" links a resource to its original source.
1078 * For example, when you save a PSD document as a JPEG, then convert the
1079 * JPEG to GIF format, the "original document ID" of both the JPEG and
1080 * GIF files is the "document ID" of the original PSD file.
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -07001081 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001082 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
Jeff Sharkeyc62b0ac2019-02-07 16:17:13 -07001083 public static final String ORIGINAL_DOCUMENT_ID = "original_document_id";
Jeff Sharkeyc8e49242018-11-02 14:34:44 -06001084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001086 /**
Mike Lockwood0b20b772010-11-04 13:16:48 -04001087 * Media provider table containing an index of all files in the media storage,
1088 * including non-media files. This should be used by applications that work with
1089 * non-media file types (text, HTML, PDF, etc) as well as applications that need to
1090 * work with multiple media file types in a single query.
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001091 */
Mike Lockwood3b2a62e2010-09-08 12:47:57 -04001092 public static final class Files {
Sudheer Shankae93db512019-01-11 16:05:28 -08001093 /** @hide */
1094 public static final String TABLE = "files";
1095
1096 /** @hide */
1097 public static final Uri EXTERNAL_CONTENT_URI = getContentUri(VOLUME_EXTERNAL);
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001098
Mike Lockwood0b20b772010-11-04 13:16:48 -04001099 /**
1100 * Get the content:// style URI for the files table on the
1101 * given volume.
1102 *
1103 * @param volumeName the name of the volume to get the URI for
1104 * @return the URI to the files table on the given volume
1105 */
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001106 public static Uri getContentUri(String volumeName) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06001107 return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("file").build();
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001108 }
1109
Mike Lockwood0b20b772010-11-04 13:16:48 -04001110 /**
1111 * Get the content:// style URI for a single row in the files table on the
1112 * given volume.
1113 *
1114 * @param volumeName the name of the volume to get the URI for
1115 * @param rowId the file to get the URI for
1116 * @return the URI to the files table on the given volume
1117 */
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001118 public static final Uri getContentUri(String volumeName,
Mike Lockwood0b20b772010-11-04 13:16:48 -04001119 long rowId) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06001120 return ContentUris.withAppendedId(getContentUri(volumeName), rowId);
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001121 }
1122
Mike Lockwood0b20b772010-11-04 13:16:48 -04001123 /**
1124 * For use only by the MTP implementation.
1125 * @hide
1126 */
Mathew Inwood6750f2e2018-08-10 09:29:25 +01001127 @UnsupportedAppUsage
Mike Lockwood8490e662010-09-09 14:16:22 -04001128 public static Uri getMtpObjectsUri(String volumeName) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06001129 return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("object").build();
Mike Lockwood8490e662010-09-09 14:16:22 -04001130 }
1131
Mike Lockwood0b20b772010-11-04 13:16:48 -04001132 /**
1133 * For use only by the MTP implementation.
1134 * @hide
1135 */
Mathew Inwood6750f2e2018-08-10 09:29:25 +01001136 @UnsupportedAppUsage
Mike Lockwood8490e662010-09-09 14:16:22 -04001137 public static final Uri getMtpObjectsUri(String volumeName,
Mike Lockwood3b2a62e2010-09-08 12:47:57 -04001138 long fileId) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06001139 return ContentUris.withAppendedId(getMtpObjectsUri(volumeName), fileId);
Mike Lockwood8490e662010-09-09 14:16:22 -04001140 }
1141
Mike Lockwood0b20b772010-11-04 13:16:48 -04001142 /**
1143 * Used to implement the MTP GetObjectReferences and SetObjectReferences commands.
1144 * @hide
1145 */
Mathew Inwood6750f2e2018-08-10 09:29:25 +01001146 @UnsupportedAppUsage
Mike Lockwood8490e662010-09-09 14:16:22 -04001147 public static final Uri getMtpReferencesUri(String volumeName,
1148 long fileId) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06001149 return getMtpObjectsUri(volumeName, fileId).buildUpon().appendPath("references")
1150 .build();
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001151 }
1152
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001153 /**
Garfield Tan93615412017-03-20 17:21:55 -07001154 * Used to trigger special logic for directories.
1155 * @hide
1156 */
1157 public static final Uri getDirectoryUri(String volumeName) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06001158 return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("dir").build();
Garfield Tan93615412017-03-20 17:21:55 -07001159 }
1160
Sudheer Shankafe7668a2018-12-16 15:52:33 -08001161 /** @hide */
1162 public static final Uri getContentUriForPath(String path) {
Jeff Sharkey1eda2ca2019-01-19 17:27:09 -07001163 return getContentUri(getVolumeName(new File(path)));
Sudheer Shankafe7668a2018-12-16 15:52:33 -08001164 }
1165
Garfield Tan93615412017-03-20 17:21:55 -07001166 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001167 * File metadata columns.
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001168 */
Mike Lockwood3b2a62e2010-09-08 12:47:57 -04001169 public interface FileColumns extends MediaColumns {
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001170 /**
Mike Lockwoodb239b6832011-04-05 10:21:27 -04001171 * The MTP storage ID of the file
Mike Lockwoodb239b6832011-04-05 10:21:27 -04001172 * @hide
1173 */
Mathew Inwood6750f2e2018-08-10 09:29:25 +01001174 @UnsupportedAppUsage
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001175 @Deprecated
1176 // @Column(Cursor.FIELD_TYPE_INTEGER)
Mike Lockwoodb239b6832011-04-05 10:21:27 -04001177 public static final String STORAGE_ID = "storage_id";
1178
1179 /**
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001180 * The MTP format code of the file
Mike Lockwood0b20b772010-11-04 13:16:48 -04001181 * @hide
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001182 */
Mathew Inwood6750f2e2018-08-10 09:29:25 +01001183 @UnsupportedAppUsage
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001184 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001185 public static final String FORMAT = "format";
1186
1187 /**
1188 * The index of the parent directory of the file
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001189 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001190 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001191 public static final String PARENT = "parent";
Mike Lockwoodfed16172010-07-09 10:46:02 -04001192
1193 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001194 * The MIME type of the media item.
1195 * <p>
1196 * This is typically defined based on the file extension of the media
1197 * item. However, it may be the value of the {@code format} attribute
1198 * defined by the <em>Dublin Core Media Initiative</em> standard,
1199 * extracted from any XMP metadata contained within this media item.
1200 * <p class="note">
1201 * Note: the {@code format} attribute may be ignored if the top-level
1202 * MIME type disagrees with the file extension. For example, it's
1203 * reasonable for an {@code image/jpeg} file to declare a {@code format}
1204 * of {@code image/vnd.google.panorama360+jpg}, but declaring a
1205 * {@code format} of {@code audio/ogg} would be ignored.
1206 * <p>
1207 * This is a read-only column that is automatically computed.
Mike Lockwoodfed16172010-07-09 10:46:02 -04001208 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001209 @Column(Cursor.FIELD_TYPE_STRING)
Mike Lockwoodc2206a02010-09-16 06:21:24 -04001210 public static final String MIME_TYPE = "mime_type";
Mike Lockwoodfed16172010-07-09 10:46:02 -04001211
1212 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001213 * The title of the media item.
Mike Lockwoodfed16172010-07-09 10:46:02 -04001214 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001215 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
Mike Lockwoodc2206a02010-09-16 06:21:24 -04001216 public static final String TITLE = "title";
1217
1218 /**
1219 * The media type (audio, video, image or playlist)
1220 * of the file, or 0 for not a media file
Mike Lockwoodc2206a02010-09-16 06:21:24 -04001221 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001222 @Column(Cursor.FIELD_TYPE_INTEGER)
Mike Lockwoodc2206a02010-09-16 06:21:24 -04001223 public static final String MEDIA_TYPE = "media_type";
1224
1225 /**
Mike Lockwooded723b42011-01-26 15:57:07 -08001226 * Constant for the {@link #MEDIA_TYPE} column indicating that file
1227 * is not an audio, image, video or playlist file.
Mike Lockwoodc2206a02010-09-16 06:21:24 -04001228 */
1229 public static final int MEDIA_TYPE_NONE = 0;
Mike Lockwooded723b42011-01-26 15:57:07 -08001230
1231 /**
1232 * Constant for the {@link #MEDIA_TYPE} column indicating that file is an image file.
1233 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -04001234 public static final int MEDIA_TYPE_IMAGE = 1;
Mike Lockwooded723b42011-01-26 15:57:07 -08001235
1236 /**
1237 * Constant for the {@link #MEDIA_TYPE} column indicating that file is an audio file.
1238 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -04001239 public static final int MEDIA_TYPE_AUDIO = 2;
Mike Lockwooded723b42011-01-26 15:57:07 -08001240
1241 /**
Ken Wakasaf76a50c2012-03-09 19:56:35 +09001242 * Constant for the {@link #MEDIA_TYPE} column indicating that file is a video file.
Mike Lockwooded723b42011-01-26 15:57:07 -08001243 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -04001244 public static final int MEDIA_TYPE_VIDEO = 3;
Mike Lockwooded723b42011-01-26 15:57:07 -08001245
1246 /**
Ken Wakasaf76a50c2012-03-09 19:56:35 +09001247 * Constant for the {@link #MEDIA_TYPE} column indicating that file is a playlist file.
Mike Lockwooded723b42011-01-26 15:57:07 -08001248 */
Mike Lockwoodc2206a02010-09-16 06:21:24 -04001249 public static final int MEDIA_TYPE_PLAYLIST = 4;
Sudheer Shanka9b98edb2018-11-15 20:29:03 -08001250
1251 /**
1252 * Column indicating if the file is part of Downloads collection.
1253 * @hide
1254 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001255 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
Sudheer Shanka9b98edb2018-11-15 20:29:03 -08001256 public static final String IS_DOWNLOAD = "is_download";
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001257 }
1258 }
1259
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001260 /** @hide */
1261 public static class ThumbnailConstants {
1262 public static final int MINI_KIND = 1;
1263 public static final int FULL_SCREEN_KIND = 2;
1264 public static final int MICRO_KIND = 3;
1265
1266 public static final Point MINI_SIZE = new Point(512, 384);
Jeff Sharkey32f6c7c2018-12-18 09:51:45 -07001267 public static final Point FULL_SCREEN_SIZE = new Point(1024, 786);
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001268 public static final Point MICRO_SIZE = new Point(96, 96);
1269 }
1270
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001271 /**
1272 * Download metadata columns.
1273 */
Sudheer Shanka9b98edb2018-11-15 20:29:03 -08001274 public interface DownloadColumns extends MediaColumns {
1275 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001276 * Uri indicating where the item has been downloaded from.
Sudheer Shanka9b98edb2018-11-15 20:29:03 -08001277 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001278 @Column(Cursor.FIELD_TYPE_STRING)
Sudheer Shanka9b98edb2018-11-15 20:29:03 -08001279 String DOWNLOAD_URI = "download_uri";
1280
1281 /**
1282 * Uri indicating HTTP referer of {@link #DOWNLOAD_URI}.
Sudheer Shanka9b98edb2018-11-15 20:29:03 -08001283 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001284 @Column(Cursor.FIELD_TYPE_STRING)
Sudheer Shanka9b98edb2018-11-15 20:29:03 -08001285 String REFERER_URI = "referer_uri";
Sudheer Shankafe7668a2018-12-16 15:52:33 -08001286
1287 /**
1288 * The description of the download.
Sudheer Shankafe7668a2018-12-16 15:52:33 -08001289 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001290 @Column(Cursor.FIELD_TYPE_STRING)
Sudheer Shankafe7668a2018-12-16 15:52:33 -08001291 String DESCRIPTION = "description";
Sudheer Shanka9b98edb2018-11-15 20:29:03 -08001292 }
1293
1294 /**
1295 * Container for downloaded files.
1296 *
1297 * <p>
1298 * Querying for downloads from this table will return files contributed via
1299 * {@link PendingSession} and also ones which were downloaded using
1300 * {@link android.app.DownloadManager} APIs.
1301 */
1302 public static final class Downloads implements DownloadColumns {
1303 private Downloads() {}
1304
1305 /**
1306 * The content:// style URI for the internal storage.
1307 */
1308 public static final Uri INTERNAL_CONTENT_URI =
1309 getContentUri("internal");
1310
1311 /**
1312 * The content:// style URI for the "primary" external storage
1313 * volume.
1314 */
1315 public static final Uri EXTERNAL_CONTENT_URI =
1316 getContentUri("external");
1317
1318 /**
Sudheer Shankaa50f1a32018-12-07 01:15:46 -08001319 * The MIME type for this table.
1320 */
1321 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/download";
1322
1323 /**
1324 * Regex that matches paths that needs to be considered part of downloads collection.
1325 * @hide
1326 */
1327 public static final Pattern PATTERN_DOWNLOADS_FILE = Pattern.compile(
1328 "(?i)^/storage/[^/]+/(?:[0-9]+/)?(?:Android/sandbox/[^/]+/)?Download/.+");
1329 private static final Pattern PATTERN_DOWNLOADS_DIRECTORY = Pattern.compile(
1330 "(?i)^/storage/[^/]+/(?:[0-9]+/)?(?:Android/sandbox/[^/]+/)?Download/?");
1331
1332 /**
Sudheer Shanka9b98edb2018-11-15 20:29:03 -08001333 * Get the content:// style URI for the downloads table on the
1334 * given volume.
1335 *
1336 * @param volumeName the name of the volume to get the URI for
1337 * @return the URI to the image media table on the given volume
1338 */
1339 public static Uri getContentUri(String volumeName) {
1340 return AUTHORITY_URI.buildUpon().appendPath(volumeName)
1341 .appendPath("downloads").build();
1342 }
1343
1344 /** @hide */
1345 public static Uri getContentUriForPath(@NonNull String path) {
Jeff Sharkey1eda2ca2019-01-19 17:27:09 -07001346 return getContentUri(getVolumeName(new File(path)));
Sudheer Shanka9b98edb2018-11-15 20:29:03 -08001347 }
Sudheer Shankaa50f1a32018-12-07 01:15:46 -08001348
1349 /** @hide */
1350 public static boolean isDownload(@NonNull String path) {
1351 return PATTERN_DOWNLOADS_FILE.matcher(path).matches();
1352 }
1353
1354 /** @hide */
1355 public static boolean isDownloadDir(@NonNull String path) {
1356 return PATTERN_DOWNLOADS_DIRECTORY.matcher(path).matches();
1357 }
Sudheer Shanka9b98edb2018-11-15 20:29:03 -08001358 }
1359
Jeff Sharkey1eda2ca2019-01-19 17:27:09 -07001360 /** {@hide} */
1361 public static @NonNull String getVolumeName(@NonNull File path) {
Jeff Sharkey8559e652019-01-20 11:21:59 -07001362 if (FileUtils.contains(Environment.getStorageDirectory(), path)) {
1363 final StorageManager sm = AppGlobals.getInitialApplication()
1364 .getSystemService(StorageManager.class);
1365 final StorageVolume sv = sm.getStorageVolume(path);
1366 if (sv != null) {
1367 if (sv.isPrimary()) {
1368 return VOLUME_EXTERNAL;
1369 } else {
Jeff Sharkey3f64ec52019-01-22 13:19:40 -07001370 return checkArgumentVolumeName(sv.getNormalizedUuid());
Jeff Sharkey8559e652019-01-20 11:21:59 -07001371 }
Sudheer Shanka9b98edb2018-11-15 20:29:03 -08001372 }
Jeff Sharkey8559e652019-01-20 11:21:59 -07001373 throw new IllegalStateException("Unknown volume at " + path);
Sudheer Shanka9b98edb2018-11-15 20:29:03 -08001374 } else {
1375 return VOLUME_INTERNAL;
1376 }
1377 }
1378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 /**
Ray Chen00c575a2009-08-28 14:12:15 -07001380 * This class is used internally by Images.Thumbnails and Video.Thumbnails, it's not intended
1381 * to be accessed elsewhere.
1382 */
Jeff Sharkey52827962018-10-18 14:44:41 -06001383 @Deprecated
Ray Chen00c575a2009-08-28 14:12:15 -07001384 private static class InternalThumbnails implements BaseColumns {
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001385 /**
1386 * Currently outstanding thumbnail requests that can be cancelled.
1387 */
1388 @GuardedBy("sPending")
1389 private static ArrayMap<Uri, CancellationSignal> sPending = new ArrayMap<>();
Ray Chenf9a243d2009-10-29 18:15:29 -07001390
Ray Chen00c575a2009-08-28 14:12:15 -07001391 /**
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001392 * Make a blocking request to obtain the given thumbnail, generating it
1393 * if needed.
Ray Chenb9944192009-09-29 20:24:01 -07001394 *
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001395 * @see #cancelThumbnail(ContentResolver, Uri)
Ray Chenb9944192009-09-29 20:24:01 -07001396 */
Jeff Sharkey52827962018-10-18 14:44:41 -06001397 @Deprecated
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001398 static @Nullable Bitmap getThumbnail(@NonNull ContentResolver cr, @NonNull Uri uri,
1399 int kind, @Nullable BitmapFactory.Options opts) {
Jeff Sharkey52827962018-10-18 14:44:41 -06001400 final Point size;
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001401 if (kind == ThumbnailConstants.MICRO_KIND) {
Jeff Sharkey52827962018-10-18 14:44:41 -06001402 size = ThumbnailConstants.MICRO_SIZE;
Jeff Sharkey32f6c7c2018-12-18 09:51:45 -07001403 } else if (kind == ThumbnailConstants.FULL_SCREEN_KIND) {
1404 size = ThumbnailConstants.FULL_SCREEN_SIZE;
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001405 } else if (kind == ThumbnailConstants.MINI_KIND) {
Jeff Sharkey52827962018-10-18 14:44:41 -06001406 size = ThumbnailConstants.MINI_SIZE;
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001407 } else {
1408 throw new IllegalArgumentException("Unsupported kind: " + kind);
Ray Chenb9944192009-09-29 20:24:01 -07001409 }
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001410
1411 CancellationSignal signal = null;
1412 synchronized (sPending) {
1413 signal = sPending.get(uri);
1414 if (signal == null) {
1415 signal = new CancellationSignal();
1416 sPending.put(uri, signal);
1417 }
Ray Chenb9944192009-09-29 20:24:01 -07001418 }
Jeff Sharkey9d0843d2013-05-07 12:41:33 -07001419
Jeff Sharkey52827962018-10-18 14:44:41 -06001420 try {
1421 return cr.loadThumbnail(uri, Point.convert(size), signal);
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001422 } catch (IOException e) {
1423 Log.w(TAG, "Failed to obtain thumbnail for " + uri, e);
1424 return null;
Ray Chen00c575a2009-08-28 14:12:15 -07001425 } finally {
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001426 synchronized (sPending) {
1427 sPending.remove(uri);
1428 }
Ray Chen00c575a2009-08-28 14:12:15 -07001429 }
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001430 }
1431
1432 /**
1433 * This method cancels the thumbnail request so clients waiting for
1434 * {@link #getThumbnail} will be interrupted and return immediately.
1435 * Only the original process which made the request can cancel their own
1436 * requests.
1437 */
Jeff Sharkey52827962018-10-18 14:44:41 -06001438 @Deprecated
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001439 static void cancelThumbnail(@NonNull ContentResolver cr, @NonNull Uri uri) {
1440 synchronized (sPending) {
1441 final CancellationSignal signal = sPending.get(uri);
1442 if (signal != null) {
1443 signal.cancel();
1444 }
1445 }
Ray Chen00c575a2009-08-28 14:12:15 -07001446 }
1447 }
1448
1449 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001450 * Collection of all media with MIME type of {@code image/*}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 */
Ray Chen00c575a2009-08-28 14:12:15 -07001452 public static final class Images {
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001453 /**
1454 * Image metadata columns.
1455 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 public interface ImageColumns extends MediaColumns {
1457 /**
1458 * The description of the image
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001460 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 public static final String DESCRIPTION = "description";
1462
1463 /**
1464 * The picasa id of the image
Jeff Sharkey7049e652018-09-13 17:05:07 -06001465 *
1466 * @deprecated this value was only relevant for images hosted on
1467 * Picasa, which are no longer supported.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 */
Jeff Sharkey7049e652018-09-13 17:05:07 -06001469 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001470 @Column(Cursor.FIELD_TYPE_STRING)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001471 public static final String PICASA_ID = "picasa_id";
1472
1473 /**
1474 * Whether the video should be published as public or private
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001475 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001476 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 public static final String IS_PRIVATE = "isprivate";
1478
1479 /**
1480 * The latitude where the image was captured.
Jeff Sharkey33e70bd2018-12-04 11:28:11 -07001481 *
1482 * @deprecated location details are no longer indexed for privacy
1483 * reasons, and this value is now always {@code null}.
1484 * You can still manually obtain location metadata using
1485 * {@link ExifInterface#getLatLong(float[])}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 */
Jeff Sharkey33e70bd2018-12-04 11:28:11 -07001487 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001488 @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 public static final String LATITUDE = "latitude";
1490
1491 /**
1492 * The longitude where the image was captured.
Jeff Sharkey33e70bd2018-12-04 11:28:11 -07001493 *
1494 * @deprecated location details are no longer indexed for privacy
1495 * reasons, and this value is now always {@code null}.
1496 * You can still manually obtain location metadata using
1497 * {@link ExifInterface#getLatLong(float[])}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 */
Jeff Sharkey33e70bd2018-12-04 11:28:11 -07001499 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001500 @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501 public static final String LONGITUDE = "longitude";
1502
1503 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001504 * The time the media item was taken.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001505 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001506 @CurrentTimeMillisLong
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001507 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001508 public static final String DATE_TAKEN = "datetaken";
1509
1510 /**
1511 * The orientation for the image expressed as degrees.
1512 * Only degrees 0, 90, 180, 270 will work.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001514 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 public static final String ORIENTATION = "orientation";
1516
1517 /**
1518 * The mini thumb id.
Jeff Sharkey7049e652018-09-13 17:05:07 -06001519 *
1520 * @deprecated all thumbnails should be obtained via
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06001521 * {@link MediaStore.Images.Thumbnails#getThumbnail}, as this
Jeff Sharkey7049e652018-09-13 17:05:07 -06001522 * value is no longer supported.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 */
Jeff Sharkey7049e652018-09-13 17:05:07 -06001524 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001525 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
1527
1528 /**
Jeff Sharkey7b148d72019-01-04 14:17:48 -07001529 * The primary bucket ID of this media item. This can be useful to
1530 * present the user a first-level clustering of related media items.
1531 * This is a read-only column that is automatically computed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001532 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001533 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534 public static final String BUCKET_ID = "bucket_id";
1535
1536 /**
Jeff Sharkey7b148d72019-01-04 14:17:48 -07001537 * The primary bucket display name of this media item. This can be
1538 * useful to present the user a first-level clustering of related
1539 * media items. This is a read-only column that is automatically
1540 * computed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001542 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
Jeff Sharkey7b148d72019-01-04 14:17:48 -07001544
1545 /**
Jeff Sharkeyc4597792019-01-30 15:14:19 -07001546 * The group ID of this media item. This can be useful to present
1547 * the user a grouping of related media items, such a burst of
1548 * images, or a {@code JPG} and {@code DNG} version of the same
1549 * image.
1550 * <p>
1551 * This is a read-only column that is automatically computed based
1552 * on the first portion of the filename. For example,
1553 * {@code IMG1024.BURST001.JPG} and {@code IMG1024.BURST002.JPG}
1554 * will have the same {@link #GROUP_ID} because the first portion of
1555 * their filenames is identical.
Jeff Sharkey7b148d72019-01-04 14:17:48 -07001556 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001557 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
Jeff Sharkeyc4597792019-01-30 15:14:19 -07001558 public static final String GROUP_ID = "group_id";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001559 }
1560
1561 public static final class Media implements ImageColumns {
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001562 /**
1563 * @deprecated all queries should be performed through
1564 * {@link ContentResolver} directly, which offers modern
1565 * features like {@link CancellationSignal}.
1566 */
1567 @Deprecated
Ray Chen00c575a2009-08-28 14:12:15 -07001568 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
1570 }
1571
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001572 /**
1573 * @deprecated all queries should be performed through
1574 * {@link ContentResolver} directly, which offers modern
1575 * features like {@link CancellationSignal}.
1576 */
1577 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection,
Ray Chen00c575a2009-08-28 14:12:15 -07001579 String where, String orderBy) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 return cr.query(uri, projection, where,
1581 null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
1582 }
1583
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001584 /**
1585 * @deprecated all queries should be performed through
1586 * {@link ContentResolver} directly, which offers modern
1587 * features like {@link CancellationSignal}.
1588 */
1589 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection,
Ray Chen00c575a2009-08-28 14:12:15 -07001591 String selection, String [] selectionArgs, String orderBy) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001592 return cr.query(uri, projection, selection,
1593 selectionArgs, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
1594 }
1595
1596 /**
1597 * Retrieves an image for the given url as a {@link Bitmap}.
1598 *
1599 * @param cr The content resolver to use
1600 * @param url The url of the image
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001601 * @deprecated loading of images should be performed through
1602 * {@link ImageDecoder#createSource(ContentResolver, Uri)},
1603 * which offers modern features like
1604 * {@link PostProcessor}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001606 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 public static final Bitmap getBitmap(ContentResolver cr, Uri url)
Ray Chen00c575a2009-08-28 14:12:15 -07001608 throws FileNotFoundException, IOException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 InputStream input = cr.openInputStream(url);
1610 Bitmap bitmap = BitmapFactory.decodeStream(input);
1611 input.close();
1612 return bitmap;
1613 }
1614
1615 /**
1616 * Insert an image and create a thumbnail for it.
1617 *
1618 * @param cr The content resolver to use
1619 * @param imagePath The path to the image to insert
1620 * @param name The name of the image
1621 * @param description The description of the image
1622 * @return The URL to the newly created image
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001623 * @deprecated inserting of images should be performed through
1624 * {@link MediaStore#createPending(Context, PendingParams)},
1625 * which offers richer control over lifecycle.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001626 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001627 @Deprecated
Ray Chen00c575a2009-08-28 14:12:15 -07001628 public static final String insertImage(ContentResolver cr, String imagePath,
1629 String name, String description) throws FileNotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 // Check if file exists with a FileInputStream
1631 FileInputStream stream = new FileInputStream(imagePath);
1632 try {
Marco Nelissen2f189fa2009-06-30 10:32:00 -07001633 Bitmap bm = BitmapFactory.decodeFile(imagePath);
1634 String ret = insertImage(cr, bm, name, description);
1635 bm.recycle();
1636 return ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001637 } finally {
1638 try {
1639 stream.close();
1640 } catch (IOException e) {
1641 }
1642 }
1643 }
1644
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001645 /**
1646 * Insert an image and create a thumbnail for it.
1647 *
1648 * @param cr The content resolver to use
1649 * @param source The stream to use for the image
1650 * @param title The name of the image
1651 * @param description The description of the image
1652 * @return The URL to the newly created image, or <code>null</code> if the image failed to be stored
1653 * for any reason.
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001654 * @deprecated inserting of images should be performed through
1655 * {@link MediaStore#createPending(Context, PendingParams)},
1656 * which offers richer control over lifecycle.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001657 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001658 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 public static final String insertImage(ContentResolver cr, Bitmap source,
Ray Chen00c575a2009-08-28 14:12:15 -07001660 String title, String description) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001661 ContentValues values = new ContentValues();
Jeff Sharkey96afa162019-01-02 11:46:48 -07001662 values.put(Images.Media.DISPLAY_NAME, title);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 values.put(Images.Media.DESCRIPTION, description);
1664 values.put(Images.Media.MIME_TYPE, "image/jpeg");
1665
1666 Uri url = null;
1667 String stringUrl = null; /* value to be returned */
1668
Ray Chen00c575a2009-08-28 14:12:15 -07001669 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670 url = cr.insert(EXTERNAL_CONTENT_URI, values);
1671
1672 if (source != null) {
1673 OutputStream imageOut = cr.openOutputStream(url);
1674 try {
1675 source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut);
1676 } finally {
1677 imageOut.close();
1678 }
1679
1680 long id = ContentUris.parseId(url);
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001681 // Block until we've generated common thumbnails
1682 Images.Thumbnails.getThumbnail(cr, id, Images.Thumbnails.MINI_KIND, null);
1683 Images.Thumbnails.getThumbnail(cr, id, Images.Thumbnails.MICRO_KIND, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 } else {
1685 Log.e(TAG, "Failed to create thumbnail, removing original");
1686 cr.delete(url, null, null);
1687 url = null;
1688 }
1689 } catch (Exception e) {
1690 Log.e(TAG, "Failed to insert image", e);
1691 if (url != null) {
1692 cr.delete(url, null, null);
1693 url = null;
1694 }
1695 }
1696
1697 if (url != null) {
1698 stringUrl = url.toString();
1699 }
1700
1701 return stringUrl;
1702 }
1703
1704 /**
1705 * Get the content:// style URI for the image media table on the
1706 * given volume.
1707 *
1708 * @param volumeName the name of the volume to get the URI for
1709 * @return the URI to the image media table on the given volume
1710 */
1711 public static Uri getContentUri(String volumeName) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06001712 return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("images")
1713 .appendPath("media").build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001714 }
1715
1716 /**
1717 * The content:// style URI for the internal storage.
1718 */
1719 public static final Uri INTERNAL_CONTENT_URI =
1720 getContentUri("internal");
1721
1722 /**
1723 * The content:// style URI for the "primary" external storage
1724 * volume.
1725 */
1726 public static final Uri EXTERNAL_CONTENT_URI =
1727 getContentUri("external");
1728
1729 /**
1730 * The MIME type of of this directory of
1731 * images. Note that each entry in this directory will have a standard
1732 * image MIME type as appropriate -- for example, image/jpeg.
1733 */
1734 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/image";
1735
1736 /**
1737 * The default sort order for this table
1738 */
1739 public static final String DEFAULT_SORT_ORDER = ImageColumns.BUCKET_DISPLAY_NAME;
Ray Chen00c575a2009-08-28 14:12:15 -07001740 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741
Ray Chen00c575a2009-08-28 14:12:15 -07001742 /**
Jeff Sharkey52827962018-10-18 14:44:41 -06001743 * This class provides utility methods to obtain thumbnails for various
1744 * {@link Images} items.
Jeff Sharkey36ee3622019-01-23 10:55:29 -07001745 *
1746 * @deprecated Callers should migrate to using
1747 * {@link ContentResolver#loadThumbnail}, since it offers
1748 * richer control over requested thumbnail sizes and
1749 * cancellation behavior.
Ray Chen00c575a2009-08-28 14:12:15 -07001750 */
Jeff Sharkey36ee3622019-01-23 10:55:29 -07001751 @Deprecated
Ray Chen00c575a2009-08-28 14:12:15 -07001752 public static class Thumbnails implements BaseColumns {
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001753 /**
1754 * @deprecated all queries should be performed through
1755 * {@link ContentResolver} directly, which offers modern
1756 * features like {@link CancellationSignal}.
1757 */
1758 @Deprecated
Ray Chen00c575a2009-08-28 14:12:15 -07001759 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
1761 }
1762
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001763 /**
1764 * @deprecated all queries should be performed through
1765 * {@link ContentResolver} directly, which offers modern
1766 * features like {@link CancellationSignal}.
1767 */
1768 @Deprecated
Ray Chen00c575a2009-08-28 14:12:15 -07001769 public static final Cursor queryMiniThumbnails(ContentResolver cr, Uri uri, int kind,
1770 String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 return cr.query(uri, projection, "kind = " + kind, null, DEFAULT_SORT_ORDER);
1772 }
1773
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001774 /**
1775 * @deprecated all queries should be performed through
1776 * {@link ContentResolver} directly, which offers modern
1777 * features like {@link CancellationSignal}.
1778 */
1779 @Deprecated
Ray Chen00c575a2009-08-28 14:12:15 -07001780 public static final Cursor queryMiniThumbnail(ContentResolver cr, long origId, int kind,
1781 String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 return cr.query(EXTERNAL_CONTENT_URI, projection,
1783 IMAGE_ID + " = " + origId + " AND " + KIND + " = " +
1784 kind, null, null);
1785 }
1786
1787 /**
Jeff Sharkey52827962018-10-18 14:44:41 -06001788 * Cancel any outstanding {@link #getThumbnail} requests, causing
1789 * them to return by throwing a {@link OperationCanceledException}.
1790 * <p>
1791 * This method has no effect on
1792 * {@link ContentResolver#loadThumbnail} calls, since they provide
1793 * their own {@link CancellationSignal}.
Ray Chenb9944192009-09-29 20:24:01 -07001794 *
Jeff Sharkey52827962018-10-18 14:44:41 -06001795 * @deprecated Callers should migrate to using
1796 * {@link ContentResolver#loadThumbnail}, since it
1797 * offers richer control over requested thumbnail sizes
1798 * and cancellation behavior.
Ray Chenb9944192009-09-29 20:24:01 -07001799 */
Jeff Sharkey52827962018-10-18 14:44:41 -06001800 @Deprecated
Ray Chenb9944192009-09-29 20:24:01 -07001801 public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001802 final Uri uri = ContentUris.withAppendedId(
1803 Images.Media.EXTERNAL_CONTENT_URI, origId);
1804 InternalThumbnails.cancelThumbnail(cr, uri);
Ray Chenb9944192009-09-29 20:24:01 -07001805 }
1806
1807 /**
Jeff Sharkey52827962018-10-18 14:44:41 -06001808 * Return thumbnail representing a specific image item. If a
1809 * thumbnail doesn't exist, this method will block until it's
1810 * generated. Callers are responsible for their own in-memory
1811 * caching of returned values.
Ray Chen00c575a2009-08-28 14:12:15 -07001812 *
Jeff Sharkey52827962018-10-18 14:44:41 -06001813 * @param imageId the image item to obtain a thumbnail for.
1814 * @param kind optimal thumbnail size desired.
1815 * @return decoded thumbnail, or {@code null} if problem was
1816 * encountered.
1817 * @deprecated Callers should migrate to using
1818 * {@link ContentResolver#loadThumbnail}, since it
1819 * offers richer control over requested thumbnail sizes
1820 * and cancellation behavior.
Ray Chen00c575a2009-08-28 14:12:15 -07001821 */
Jeff Sharkey52827962018-10-18 14:44:41 -06001822 @Deprecated
1823 public static Bitmap getThumbnail(ContentResolver cr, long imageId, int kind,
Ray Chen00c575a2009-08-28 14:12:15 -07001824 BitmapFactory.Options options) {
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001825 final Uri uri = ContentUris.withAppendedId(
Jeff Sharkey52827962018-10-18 14:44:41 -06001826 Images.Media.EXTERNAL_CONTENT_URI, imageId);
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001827 return InternalThumbnails.getThumbnail(cr, uri, kind, options);
Ray Chen13ed5752009-10-05 12:21:24 -07001828 }
1829
1830 /**
Jeff Sharkey52827962018-10-18 14:44:41 -06001831 * Cancel any outstanding {@link #getThumbnail} requests, causing
1832 * them to return by throwing a {@link OperationCanceledException}.
1833 * <p>
1834 * This method has no effect on
1835 * {@link ContentResolver#loadThumbnail} calls, since they provide
1836 * their own {@link CancellationSignal}.
Ray Chen13ed5752009-10-05 12:21:24 -07001837 *
Jeff Sharkey52827962018-10-18 14:44:41 -06001838 * @deprecated Callers should migrate to using
1839 * {@link ContentResolver#loadThumbnail}, since it
1840 * offers richer control over requested thumbnail sizes
1841 * and cancellation behavior.
Ray Chen13ed5752009-10-05 12:21:24 -07001842 */
Jeff Sharkey52827962018-10-18 14:44:41 -06001843 @Deprecated
1844 public static void cancelThumbnailRequest(ContentResolver cr, long origId,
1845 long groupId) {
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001846 cancelThumbnailRequest(cr, origId);
Ray Chen13ed5752009-10-05 12:21:24 -07001847 }
1848
1849 /**
Jeff Sharkey52827962018-10-18 14:44:41 -06001850 * Return thumbnail representing a specific image item. If a
1851 * thumbnail doesn't exist, this method will block until it's
1852 * generated. Callers are responsible for their own in-memory
1853 * caching of returned values.
Ray Chen13ed5752009-10-05 12:21:24 -07001854 *
Jeff Sharkey52827962018-10-18 14:44:41 -06001855 * @param imageId the image item to obtain a thumbnail for.
1856 * @param kind optimal thumbnail size desired.
1857 * @return decoded thumbnail, or {@code null} if problem was
1858 * encountered.
1859 * @deprecated Callers should migrate to using
1860 * {@link ContentResolver#loadThumbnail}, since it
1861 * offers richer control over requested thumbnail sizes
1862 * and cancellation behavior.
Ray Chen13ed5752009-10-05 12:21:24 -07001863 */
Jeff Sharkey52827962018-10-18 14:44:41 -06001864 @Deprecated
1865 public static Bitmap getThumbnail(ContentResolver cr, long imageId, long groupId,
Ray Chen13ed5752009-10-05 12:21:24 -07001866 int kind, BitmapFactory.Options options) {
Jeff Sharkey52827962018-10-18 14:44:41 -06001867 return getThumbnail(cr, imageId, kind, options);
Ray Chen00c575a2009-08-28 14:12:15 -07001868 }
1869
1870 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 * Get the content:// style URI for the image media table on the
1872 * given volume.
1873 *
1874 * @param volumeName the name of the volume to get the URI for
1875 * @return the URI to the image media table on the given volume
1876 */
1877 public static Uri getContentUri(String volumeName) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06001878 return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("images")
1879 .appendPath("thumbnails").build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 }
1881
1882 /**
1883 * The content:// style URI for the internal storage.
1884 */
1885 public static final Uri INTERNAL_CONTENT_URI =
1886 getContentUri("internal");
1887
1888 /**
1889 * The content:// style URI for the "primary" external storage
1890 * volume.
1891 */
1892 public static final Uri EXTERNAL_CONTENT_URI =
1893 getContentUri("external");
1894
1895 /**
1896 * The default sort order for this table
1897 */
1898 public static final String DEFAULT_SORT_ORDER = "image_id ASC";
1899
1900 /**
Jeff Sharkey60cfad82016-01-05 17:30:57 -07001901 * Path to the thumbnail file on disk.
1902 * <p>
1903 * Note that apps may not have filesystem permissions to directly
1904 * access this path. Instead of trying to open this path directly,
1905 * apps should use
1906 * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
1907 * access.
Jeff Sharkey52827962018-10-18 14:44:41 -06001908 *
1909 * @deprecated Apps may not have filesystem permissions to directly
1910 * access this path. Instead of trying to open this path
1911 * directly, apps should use
1912 * {@link ContentResolver#loadThumbnail}
1913 * to gain access. This value will always be
1914 * {@code NULL} for apps targeting
1915 * {@link android.os.Build.VERSION_CODES#Q} or higher.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 */
Jeff Sharkey52827962018-10-18 14:44:41 -06001917 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001918 @Column(Cursor.FIELD_TYPE_STRING)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001919 public static final String DATA = "_data";
1920
1921 /**
1922 * The original image for the thumbnal
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001924 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001925 public static final String IMAGE_ID = "image_id";
1926
1927 /**
1928 * The kind of the thumbnail
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001930 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001931 public static final String KIND = "kind";
1932
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06001933 public static final int MINI_KIND = ThumbnailConstants.MINI_KIND;
1934 public static final int FULL_SCREEN_KIND = ThumbnailConstants.FULL_SCREEN_KIND;
1935 public static final int MICRO_KIND = ThumbnailConstants.MICRO_KIND;
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001936
Ray Chen00c575a2009-08-28 14:12:15 -07001937 /**
1938 * The blob raw data of thumbnail
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001939 *
1940 * @deprecated this column never existed internally, and could never
1941 * have returned valid data.
Ray Chen00c575a2009-08-28 14:12:15 -07001942 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001943 @Deprecated
1944 @Column(Cursor.FIELD_TYPE_BLOB)
Ray Chen00c575a2009-08-28 14:12:15 -07001945 public static final String THUMB_DATA = "thumb_data";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001946
1947 /**
1948 * The width of the thumbnal
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001949 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001950 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001951 public static final String WIDTH = "width";
1952
1953 /**
1954 * The height of the thumbnail
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001956 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001957 public static final String HEIGHT = "height";
1958 }
1959 }
1960
1961 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001962 * Collection of all media with MIME type of {@code audio/*}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001963 */
1964 public static final class Audio {
1965 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001966 * Audio metadata columns.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967 */
1968 public interface AudioColumns extends MediaColumns {
1969
1970 /**
1971 * A non human readable key calculated from the TITLE, used for
1972 * searching, sorting and grouping
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001973 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001974 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 public static final String TITLE_KEY = "title_key";
1976
1977 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001978 * The duration of the audio item.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001980 @DurationMillisLong
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001981 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001982 public static final String DURATION = "duration";
1983
1984 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001985 * The position within the audio item at which playback should be
1986 * resumed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07001988 @DurationMillisLong
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001989 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 public static final String BOOKMARK = "bookmark";
1991
1992 /**
1993 * The id of the artist who created the audio file, if any
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07001995 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001996 public static final String ARTIST_ID = "artist_id";
1997
1998 /**
1999 * The artist who created the audio file, if any
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002001 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 public static final String ARTIST = "artist";
2003
2004 /**
Marco Nelissenabc28192010-03-18 17:10:38 -07002005 * The artist credited for the album that contains the audio file
Marco Nelissenabc28192010-03-18 17:10:38 -07002006 * @hide
2007 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002008 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
Marco Nelissenabc28192010-03-18 17:10:38 -07002009 public static final String ALBUM_ARTIST = "album_artist";
2010
2011 /**
Marco Nelissenee35aff2011-01-06 11:12:17 -08002012 * Whether the song is part of a compilation
Marco Nelissenee35aff2011-01-06 11:12:17 -08002013 * @hide
2014 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002015 @Deprecated
2016 // @Column(Cursor.FIELD_TYPE_STRING)
Marco Nelissenee35aff2011-01-06 11:12:17 -08002017 public static final String COMPILATION = "compilation";
2018
2019 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 * A non human readable key calculated from the ARTIST, used for
2021 * searching, sorting and grouping
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002022 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002023 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 public static final String ARTIST_KEY = "artist_key";
2025
2026 /**
2027 * The composer of the audio file, if any
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002028 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002029 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002030 public static final String COMPOSER = "composer";
2031
2032 /**
2033 * The id of the album the audio file is from, if any
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002034 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002035 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036 public static final String ALBUM_ID = "album_id";
2037
2038 /**
2039 * The album the audio file is from, if any
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002041 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002042 public static final String ALBUM = "album";
2043
2044 /**
2045 * A non human readable key calculated from the ALBUM, used for
2046 * searching, sorting and grouping
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002047 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002048 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002049 public static final String ALBUM_KEY = "album_key";
2050
2051 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 * The track number of this song on the album, if any.
2053 * This number encodes both the track number and the
2054 * disc number. For multi-disc sets, this number will
2055 * be 1xxx for tracks on the first disc, 2xxx for tracks
2056 * on the second disc, etc.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002057 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002058 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002059 public static final String TRACK = "track";
2060
2061 /**
2062 * The year the audio file was recorded, if any
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002063 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002064 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002065 public static final String YEAR = "year";
2066
2067 /**
2068 * Non-zero if the audio file is music
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002070 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002071 public static final String IS_MUSIC = "is_music";
2072
2073 /**
2074 * Non-zero if the audio file is a podcast
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002075 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002076 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002077 public static final String IS_PODCAST = "is_podcast";
2078
2079 /**
Gloria Wang82428a82011-06-27 11:09:00 -07002080 * Non-zero if the audio file may be a ringtone
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002081 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002082 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 public static final String IS_RINGTONE = "is_ringtone";
2084
2085 /**
Gloria Wang82428a82011-06-27 11:09:00 -07002086 * Non-zero if the audio file may be an alarm
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002087 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002088 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002089 public static final String IS_ALARM = "is_alarm";
2090
2091 /**
Gloria Wang82428a82011-06-27 11:09:00 -07002092 * Non-zero if the audio file may be a notification sound
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002093 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002094 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002095 public static final String IS_NOTIFICATION = "is_notification";
Mike Lockwoode5d04952011-07-30 09:58:35 -04002096
2097 /**
Jeff Sharkey10887d52018-11-30 13:44:41 -07002098 * Non-zero if the audio file is an audiobook
Jeff Sharkey10887d52018-11-30 13:44:41 -07002099 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002100 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
Jeff Sharkey10887d52018-11-30 13:44:41 -07002101 public static final String IS_AUDIOBOOK = "is_audiobook";
2102
2103 /**
Mike Lockwoode5d04952011-07-30 09:58:35 -04002104 * The genre of the audio file, if any
Mike Lockwoode5d04952011-07-30 09:58:35 -04002105 * Does not exist in the database - only used by the media scanner for inserts.
2106 * @hide
2107 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002108 @Deprecated
2109 // @Column(Cursor.FIELD_TYPE_STRING)
Mike Lockwoode5d04952011-07-30 09:58:35 -04002110 public static final String GENRE = "genre";
Sean Stout87313542017-09-08 11:21:16 -07002111
2112 /**
2113 * The resource URI of a localized title, if any
Sean Stout87313542017-09-08 11:21:16 -07002114 * Conforms to this pattern:
2115 * Scheme: {@link ContentResolver.SCHEME_ANDROID_RESOURCE}
2116 * Authority: Package Name of ringtone title provider
2117 * First Path Segment: Type of resource (must be "string")
2118 * Second Path Segment: Resource ID of title
2119 * @hide
2120 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002121 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
Sean Stout87313542017-09-08 11:21:16 -07002122 public static final String TITLE_RESOURCE_URI = "title_resource_uri";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002123 }
2124
2125 /**
2126 * Converts a name to a "key" that can be used for grouping, sorting
2127 * and searching.
2128 * The rules that govern this conversion are:
2129 * - remove 'special' characters like ()[]'!?.,
2130 * - remove leading/trailing spaces
2131 * - convert everything to lowercase
2132 * - remove leading "the ", "an " and "a "
2133 * - remove trailing ", the|an|a"
2134 * - remove accents. This step leaves us with CollationKey data,
2135 * which is not human readable
2136 *
2137 * @param name The artist or album name to convert
2138 * @return The "key" for the given name.
2139 */
2140 public static String keyFor(String name) {
2141 if (name != null) {
Marco Nelissen816cf522009-07-06 09:19:10 -07002142 boolean sortfirst = false;
Marco Nelissen9a488b42010-01-04 15:09:03 -08002143 if (name.equals(UNKNOWN_STRING)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002144 return "\001";
2145 }
Marco Nelissen816cf522009-07-06 09:19:10 -07002146 // Check if the first character is \001. We use this to
2147 // force sorting of certain special files, like the silent ringtone.
2148 if (name.startsWith("\001")) {
2149 sortfirst = true;
2150 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002151 name = name.trim().toLowerCase();
2152 if (name.startsWith("the ")) {
2153 name = name.substring(4);
2154 }
2155 if (name.startsWith("an ")) {
2156 name = name.substring(3);
2157 }
2158 if (name.startsWith("a ")) {
2159 name = name.substring(2);
2160 }
2161 if (name.endsWith(", the") || name.endsWith(",the") ||
2162 name.endsWith(", an") || name.endsWith(",an") ||
2163 name.endsWith(", a") || name.endsWith(",a")) {
2164 name = name.substring(0, name.lastIndexOf(','));
2165 }
Marco Nelissene754e122009-05-22 12:16:58 -07002166 name = name.replaceAll("[\\[\\]\\(\\)\"'.,?!]", "").trim();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167 if (name.length() > 0) {
2168 // Insert a separator between the characters to avoid
2169 // matches on a partial character. If we ever change
2170 // to start-of-word-only matches, this can be removed.
2171 StringBuilder b = new StringBuilder();
2172 b.append('.');
2173 int nl = name.length();
2174 for (int i = 0; i < nl; i++) {
2175 b.append(name.charAt(i));
2176 b.append('.');
2177 }
2178 name = b.toString();
Marco Nelissen816cf522009-07-06 09:19:10 -07002179 String key = DatabaseUtils.getCollationKey(name);
2180 if (sortfirst) {
2181 key = "\001" + key;
2182 }
2183 return key;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 } else {
2185 return "";
2186 }
2187 }
2188 return null;
2189 }
2190
2191 public static final class Media implements AudioColumns {
2192 /**
2193 * Get the content:// style URI for the audio media table on the
2194 * given volume.
2195 *
2196 * @param volumeName the name of the volume to get the URI for
2197 * @return the URI to the audio media table on the given volume
2198 */
2199 public static Uri getContentUri(String volumeName) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06002200 return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
2201 .appendPath("media").build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002202 }
2203
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06002204 /**
2205 * Get the content:// style URI for the given audio media file.
2206 *
2207 * @deprecated Apps may not have filesystem permissions to directly
2208 * access this path.
2209 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002210 @Deprecated
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06002211 public static @Nullable Uri getContentUriForPath(@NonNull String path) {
Jeff Sharkey1eda2ca2019-01-19 17:27:09 -07002212 return getContentUri(getVolumeName(new File(path)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 }
2214
2215 /**
2216 * The content:// style URI for the internal storage.
2217 */
2218 public static final Uri INTERNAL_CONTENT_URI =
2219 getContentUri("internal");
2220
2221 /**
2222 * The content:// style URI for the "primary" external storage
2223 * volume.
2224 */
2225 public static final Uri EXTERNAL_CONTENT_URI =
2226 getContentUri("external");
2227
2228 /**
2229 * The MIME type for this table.
2230 */
2231 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
2232
2233 /**
Matt Caseybd7bcf02014-02-05 15:51:39 -08002234 * The MIME type for an audio track.
2235 */
2236 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/audio";
2237
2238 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002239 * The default sort order for this table
2240 */
Marco Nelissen816cf522009-07-06 09:19:10 -07002241 public static final String DEFAULT_SORT_ORDER = TITLE_KEY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002242
2243 /**
2244 * Activity Action: Start SoundRecorder application.
2245 * <p>Input: nothing.
2246 * <p>Output: An uri to the recorded sound stored in the Media Library
2247 * if the recording was successful.
2248 * May also contain the extra EXTRA_MAX_BYTES.
2249 * @see #EXTRA_MAX_BYTES
2250 */
Jeff Sharkey0f3f60b2017-04-24 18:06:20 -06002251 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002252 public static final String RECORD_SOUND_ACTION =
2253 "android.provider.MediaStore.RECORD_SOUND";
2254
2255 /**
2256 * The name of the Intent-extra used to define a maximum file size for
2257 * a recording made by the SoundRecorder application.
2258 *
2259 * @see #RECORD_SOUND_ACTION
2260 */
2261 public static final String EXTRA_MAX_BYTES =
2262 "android.provider.MediaStore.extra.MAX_BYTES";
2263 }
2264
2265 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002266 * Audio genre metadata columns.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002267 */
2268 public interface GenresColumns {
2269 /**
2270 * The name of the genre
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002271 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002272 @Column(Cursor.FIELD_TYPE_STRING)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002273 public static final String NAME = "name";
2274 }
2275
2276 /**
2277 * Contains all genres for audio files
2278 */
2279 public static final class Genres implements BaseColumns, GenresColumns {
2280 /**
2281 * Get the content:// style URI for the audio genres table on the
2282 * given volume.
2283 *
2284 * @param volumeName the name of the volume to get the URI for
2285 * @return the URI to the audio genres table on the given volume
2286 */
2287 public static Uri getContentUri(String volumeName) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06002288 return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
2289 .appendPath("genres").build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002290 }
2291
2292 /**
Mike Lockwoodbdb05df2010-09-26 12:33:25 -04002293 * Get the content:// style URI for querying the genres of an audio file.
2294 *
2295 * @param volumeName the name of the volume to get the URI for
2296 * @param audioId the ID of the audio file for which to retrieve the genres
2297 * @return the URI to for querying the genres for the audio file
2298 * with the given the volume and audioID
2299 */
2300 public static Uri getContentUriForAudioId(String volumeName, int audioId) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06002301 return ContentUris.withAppendedId(Audio.Media.getContentUri(volumeName), audioId)
2302 .buildUpon().appendPath("genres").build();
Mike Lockwoodbdb05df2010-09-26 12:33:25 -04002303 }
2304
2305 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002306 * The content:// style URI for the internal storage.
2307 */
2308 public static final Uri INTERNAL_CONTENT_URI =
2309 getContentUri("internal");
2310
2311 /**
2312 * The content:// style URI for the "primary" external storage
2313 * volume.
2314 */
2315 public static final Uri EXTERNAL_CONTENT_URI =
2316 getContentUri("external");
2317
2318 /**
2319 * The MIME type for this table.
2320 */
2321 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/genre";
2322
2323 /**
2324 * The MIME type for entries in this table.
2325 */
2326 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/genre";
2327
2328 /**
2329 * The default sort order for this table
2330 */
2331 public static final String DEFAULT_SORT_ORDER = NAME;
2332
2333 /**
2334 * Sub-directory of each genre containing all members.
2335 */
2336 public static final class Members implements AudioColumns {
2337
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06002338 public static final Uri getContentUri(String volumeName, long genreId) {
2339 return ContentUris
2340 .withAppendedId(Audio.Genres.getContentUri(volumeName), genreId)
2341 .buildUpon().appendPath("members").build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002342 }
2343
2344 /**
2345 * A subdirectory of each genre containing all member audio files.
2346 */
2347 public static final String CONTENT_DIRECTORY = "members";
2348
2349 /**
2350 * The default sort order for this table
2351 */
Marco Nelissen816cf522009-07-06 09:19:10 -07002352 public static final String DEFAULT_SORT_ORDER = TITLE_KEY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002353
2354 /**
2355 * The ID of the audio file
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002356 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002357 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002358 public static final String AUDIO_ID = "audio_id";
2359
2360 /**
2361 * The ID of the genre
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002362 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002363 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002364 public static final String GENRE_ID = "genre_id";
2365 }
2366 }
2367
2368 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002369 * Audio playlist metadata columns.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002370 */
2371 public interface PlaylistsColumns {
2372 /**
2373 * The name of the playlist
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002374 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002375 @Column(Cursor.FIELD_TYPE_STRING)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002376 public static final String NAME = "name";
2377
2378 /**
Jeff Sharkey60cfad82016-01-05 17:30:57 -07002379 * Path to the playlist file on disk.
2380 * <p>
2381 * Note that apps may not have filesystem permissions to directly
2382 * access this path. Instead of trying to open this path directly,
2383 * apps should use
2384 * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
2385 * access.
Jeff Sharkey52827962018-10-18 14:44:41 -06002386 *
2387 * @deprecated Apps may not have filesystem permissions to directly
2388 * access this path. Instead of trying to open this path
2389 * directly, apps should use
2390 * {@link ContentResolver#openFileDescriptor(Uri, String)}
2391 * to gain access. This value will always be
2392 * {@code NULL} for apps targeting
2393 * {@link android.os.Build.VERSION_CODES#Q} or higher.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002394 */
Jeff Sharkey52827962018-10-18 14:44:41 -06002395 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002396 @Column(Cursor.FIELD_TYPE_STRING)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002397 public static final String DATA = "_data";
2398
2399 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002400 * The time the media item was first added.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002401 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002402 @CurrentTimeSecondsLong
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002403 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002404 public static final String DATE_ADDED = "date_added";
2405
2406 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002407 * The time the media item was last modified.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002408 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002409 @CurrentTimeSecondsLong
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002410 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002411 public static final String DATE_MODIFIED = "date_modified";
2412 }
2413
2414 /**
2415 * Contains playlists for audio files
2416 */
2417 public static final class Playlists implements BaseColumns,
2418 PlaylistsColumns {
2419 /**
2420 * Get the content:// style URI for the audio playlists table on the
2421 * given volume.
2422 *
2423 * @param volumeName the name of the volume to get the URI for
2424 * @return the URI to the audio playlists table on the given volume
2425 */
2426 public static Uri getContentUri(String volumeName) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06002427 return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
2428 .appendPath("playlists").build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002429 }
2430
2431 /**
2432 * The content:// style URI for the internal storage.
2433 */
2434 public static final Uri INTERNAL_CONTENT_URI =
2435 getContentUri("internal");
2436
2437 /**
2438 * The content:// style URI for the "primary" external storage
2439 * volume.
2440 */
2441 public static final Uri EXTERNAL_CONTENT_URI =
2442 getContentUri("external");
2443
2444 /**
2445 * The MIME type for this table.
2446 */
2447 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/playlist";
2448
2449 /**
2450 * The MIME type for entries in this table.
2451 */
2452 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/playlist";
2453
2454 /**
2455 * The default sort order for this table
2456 */
2457 public static final String DEFAULT_SORT_ORDER = NAME;
2458
2459 /**
2460 * Sub-directory of each playlist containing all members.
2461 */
2462 public static final class Members implements AudioColumns {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06002463 public static final Uri getContentUri(String volumeName, long playlistId) {
2464 return ContentUris
2465 .withAppendedId(Audio.Playlists.getContentUri(volumeName), playlistId)
2466 .buildUpon().appendPath("members").build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002467 }
2468
2469 /**
Marco Nelissene3d05fc2009-12-09 16:01:46 -08002470 * Convenience method to move a playlist item to a new location
2471 * @param res The content resolver to use
2472 * @param playlistId The numeric id of the playlist
2473 * @param from The position of the item to move
2474 * @param to The position to move the item to
2475 * @return true on success
Marco Nelissene3d05fc2009-12-09 16:01:46 -08002476 */
2477 public static final boolean moveItem(ContentResolver res,
2478 long playlistId, int from, int to) {
2479 Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external",
2480 playlistId)
2481 .buildUpon()
2482 .appendEncodedPath(String.valueOf(from))
2483 .appendQueryParameter("move", "true")
2484 .build();
2485 ContentValues values = new ContentValues();
2486 values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, to);
2487 return res.update(uri, values, null, null) != 0;
2488 }
2489
2490 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002491 * The ID within the playlist.
2492 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002493 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002494 public static final String _ID = "_id";
2495
2496 /**
2497 * A subdirectory of each playlist containing all member audio
2498 * files.
2499 */
2500 public static final String CONTENT_DIRECTORY = "members";
2501
2502 /**
2503 * The ID of the audio file
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002504 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002505 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002506 public static final String AUDIO_ID = "audio_id";
2507
2508 /**
2509 * The ID of the playlist
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002510 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002511 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002512 public static final String PLAYLIST_ID = "playlist_id";
2513
2514 /**
2515 * The order of the songs in the playlist
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002517 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002518 public static final String PLAY_ORDER = "play_order";
2519
2520 /**
2521 * The default sort order for this table
2522 */
2523 public static final String DEFAULT_SORT_ORDER = PLAY_ORDER;
2524 }
2525 }
2526
2527 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002528 * Audio artist metadata columns.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002529 */
2530 public interface ArtistColumns {
2531 /**
2532 * The artist who created the audio file, if any
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002533 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002534 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002535 public static final String ARTIST = "artist";
2536
2537 /**
2538 * A non human readable key calculated from the ARTIST, used for
2539 * searching, sorting and grouping
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002540 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002541 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002542 public static final String ARTIST_KEY = "artist_key";
2543
2544 /**
2545 * The number of albums in the database for this artist
2546 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002547 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002548 public static final String NUMBER_OF_ALBUMS = "number_of_albums";
2549
2550 /**
2551 * The number of albums in the database for this artist
2552 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002553 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002554 public static final String NUMBER_OF_TRACKS = "number_of_tracks";
2555 }
2556
2557 /**
2558 * Contains artists for audio files
2559 */
2560 public static final class Artists implements BaseColumns, ArtistColumns {
2561 /**
2562 * Get the content:// style URI for the artists table on the
2563 * given volume.
2564 *
2565 * @param volumeName the name of the volume to get the URI for
2566 * @return the URI to the audio artists table on the given volume
2567 */
2568 public static Uri getContentUri(String volumeName) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06002569 return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
2570 .appendPath("artists").build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002571 }
2572
2573 /**
2574 * The content:// style URI for the internal storage.
2575 */
2576 public static final Uri INTERNAL_CONTENT_URI =
2577 getContentUri("internal");
2578
2579 /**
2580 * The content:// style URI for the "primary" external storage
2581 * volume.
2582 */
2583 public static final Uri EXTERNAL_CONTENT_URI =
2584 getContentUri("external");
2585
2586 /**
2587 * The MIME type for this table.
2588 */
2589 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/artists";
2590
2591 /**
2592 * The MIME type for entries in this table.
2593 */
2594 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/artist";
2595
2596 /**
2597 * The default sort order for this table
2598 */
2599 public static final String DEFAULT_SORT_ORDER = ARTIST_KEY;
2600
2601 /**
2602 * Sub-directory of each artist containing all albums on which
2603 * a song by the artist appears.
2604 */
2605 public static final class Albums implements AlbumColumns {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06002606 public static final Uri getContentUri(String volumeName,long artistId) {
2607 return ContentUris
2608 .withAppendedId(Audio.Artists.getContentUri(volumeName), artistId)
2609 .buildUpon().appendPath("albums").build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002610 }
2611 }
2612 }
2613
2614 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002615 * Audio album metadata columns.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002616 */
2617 public interface AlbumColumns {
2618
2619 /**
2620 * The id for the album
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002621 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002622 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002623 public static final String ALBUM_ID = "album_id";
2624
2625 /**
2626 * The album on which the audio file appears, if any
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002627 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002628 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002629 public static final String ALBUM = "album";
2630
2631 /**
2632 * The artist whose songs appear on this album
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002633 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002634 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002635 public static final String ARTIST = "artist";
2636
2637 /**
2638 * The number of songs on this album
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002639 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002640 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002641 public static final String NUMBER_OF_SONGS = "numsongs";
2642
2643 /**
2644 * This column is available when getting album info via artist,
2645 * and indicates the number of songs on the album by the given
2646 * artist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002648 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002649 public static final String NUMBER_OF_SONGS_FOR_ARTIST = "numsongs_by_artist";
2650
2651 /**
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07002652 * The year in which the earliest songs
2653 * on this album were released. This will often
2654 * be the same as {@link #LAST_YEAR}, but for compilation albums
2655 * they might differ.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002656 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002657 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002658 public static final String FIRST_YEAR = "minyear";
Ray Chen00c575a2009-08-28 14:12:15 -07002659
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07002660 /**
2661 * The year in which the latest songs
2662 * on this album were released. This will often
2663 * be the same as {@link #FIRST_YEAR}, but for compilation albums
2664 * they might differ.
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07002665 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002666 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002667 public static final String LAST_YEAR = "maxyear";
2668
2669 /**
2670 * A non human readable key calculated from the ALBUM, used for
2671 * searching, sorting and grouping
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002672 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002673 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002674 public static final String ALBUM_KEY = "album_key";
2675
2676 /**
2677 * Cached album art.
Jeff Sharkey52827962018-10-18 14:44:41 -06002678 *
2679 * @deprecated Apps may not have filesystem permissions to directly
2680 * access this path. Instead of trying to open this path
2681 * directly, apps should use
2682 * {@link ContentResolver#loadThumbnail}
2683 * to gain access. This value will always be
2684 * {@code NULL} for apps targeting
2685 * {@link android.os.Build.VERSION_CODES#Q} or higher.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002686 */
Jeff Sharkey52827962018-10-18 14:44:41 -06002687 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002688 @Column(Cursor.FIELD_TYPE_STRING)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002689 public static final String ALBUM_ART = "album_art";
2690 }
2691
2692 /**
2693 * Contains artists for audio files
2694 */
2695 public static final class Albums implements BaseColumns, AlbumColumns {
2696 /**
2697 * Get the content:// style URI for the albums table on the
2698 * given volume.
2699 *
2700 * @param volumeName the name of the volume to get the URI for
2701 * @return the URI to the audio albums table on the given volume
2702 */
2703 public static Uri getContentUri(String volumeName) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06002704 return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("audio")
2705 .appendPath("albums").build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002706 }
2707
2708 /**
2709 * The content:// style URI for the internal storage.
2710 */
2711 public static final Uri INTERNAL_CONTENT_URI =
2712 getContentUri("internal");
2713
2714 /**
2715 * The content:// style URI for the "primary" external storage
2716 * volume.
2717 */
2718 public static final Uri EXTERNAL_CONTENT_URI =
2719 getContentUri("external");
2720
2721 /**
2722 * The MIME type for this table.
2723 */
2724 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/albums";
2725
2726 /**
2727 * The MIME type for entries in this table.
2728 */
2729 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/album";
2730
2731 /**
2732 * The default sort order for this table
2733 */
2734 public static final String DEFAULT_SORT_ORDER = ALBUM_KEY;
2735 }
Matt Caseybd7bcf02014-02-05 15:51:39 -08002736
2737 public static final class Radio {
2738 /**
2739 * The MIME type for entries in this table.
2740 */
2741 public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/radio";
Matt Caseyde6f4702014-06-06 10:16:15 -07002742
2743 // Not instantiable.
2744 private Radio() { }
Matt Caseybd7bcf02014-02-05 15:51:39 -08002745 }
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002746
2747 /**
2748 * This class provides utility methods to obtain thumbnails for various
2749 * {@link Audio} items.
2750 *
2751 * @deprecated Callers should migrate to using
2752 * {@link ContentResolver#loadThumbnail}, since it offers
2753 * richer control over requested thumbnail sizes and
2754 * cancellation behavior.
2755 * @hide
2756 */
2757 @Deprecated
2758 public static class Thumbnails implements BaseColumns {
2759 /**
2760 * Path to the thumbnail file on disk.
2761 * <p>
2762 * Note that apps may not have filesystem permissions to directly
2763 * access this path. Instead of trying to open this path directly,
2764 * apps should use
2765 * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
2766 * access.
2767 *
2768 * @deprecated Apps may not have filesystem permissions to directly
2769 * access this path. Instead of trying to open this path
2770 * directly, apps should use
2771 * {@link ContentResolver#loadThumbnail}
2772 * to gain access. This value will always be
2773 * {@code NULL} for apps targeting
2774 * {@link android.os.Build.VERSION_CODES#Q} or higher.
2775 */
2776 @Deprecated
2777 @Column(Cursor.FIELD_TYPE_STRING)
2778 public static final String DATA = "_data";
2779
2780 @Column(Cursor.FIELD_TYPE_INTEGER)
2781 public static final String ALBUM_ID = "album_id";
2782 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002783 }
2784
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002785 /**
2786 * Collection of all media with MIME type of {@code video/*}.
2787 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002788 public static final class Video {
2789
2790 /**
2791 * The default sort order for this table.
2792 */
2793 public static final String DEFAULT_SORT_ORDER = MediaColumns.DISPLAY_NAME;
2794
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002795 /**
2796 * @deprecated all queries should be performed through
2797 * {@link ContentResolver} directly, which offers modern
2798 * features like {@link CancellationSignal}.
2799 */
2800 @Deprecated
Ray Chen00c575a2009-08-28 14:12:15 -07002801 public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002802 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
2803 }
2804
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002805 /**
2806 * Video metadata columns.
2807 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002808 public interface VideoColumns extends MediaColumns {
2809
2810 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002811 * The duration of the video item.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002812 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002813 @DurationMillisLong
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002814 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002815 public static final String DURATION = "duration";
2816
2817 /**
2818 * The artist who created the video file, if any
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002819 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002820 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002821 public static final String ARTIST = "artist";
2822
2823 /**
2824 * The album the video file is from, if any
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002825 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002826 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002827 public static final String ALBUM = "album";
2828
2829 /**
2830 * The resolution of the video file, formatted as "XxY"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002831 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002832 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002833 public static final String RESOLUTION = "resolution";
2834
2835 /**
2836 * The description of the video recording
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002837 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002838 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002839 public static final String DESCRIPTION = "description";
2840
2841 /**
2842 * Whether the video should be published as public or private
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002843 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002844 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002845 public static final String IS_PRIVATE = "isprivate";
2846
2847 /**
2848 * The user-added tags associated with a video
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002849 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002850 @Column(Cursor.FIELD_TYPE_STRING)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002851 public static final String TAGS = "tags";
2852
2853 /**
2854 * The YouTube category of the video
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002855 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002856 @Column(Cursor.FIELD_TYPE_STRING)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002857 public static final String CATEGORY = "category";
2858
2859 /**
2860 * The language of the video
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002861 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002862 @Column(Cursor.FIELD_TYPE_STRING)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002863 public static final String LANGUAGE = "language";
2864
2865 /**
Casey Hoc3898822012-03-02 16:32:09 -08002866 * The latitude where the video was captured.
Jeff Sharkey33e70bd2018-12-04 11:28:11 -07002867 *
2868 * @deprecated location details are no longer indexed for privacy
2869 * reasons, and this value is now always {@code null}.
2870 * You can still manually obtain location metadata using
2871 * {@link ExifInterface#getLatLong(float[])}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002872 */
Jeff Sharkey33e70bd2018-12-04 11:28:11 -07002873 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002874 @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002875 public static final String LATITUDE = "latitude";
2876
2877 /**
Casey Hoc3898822012-03-02 16:32:09 -08002878 * The longitude where the video was captured.
Jeff Sharkey33e70bd2018-12-04 11:28:11 -07002879 *
2880 * @deprecated location details are no longer indexed for privacy
2881 * reasons, and this value is now always {@code null}.
2882 * You can still manually obtain location metadata using
2883 * {@link ExifInterface#getLatLong(float[])}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002884 */
Jeff Sharkey33e70bd2018-12-04 11:28:11 -07002885 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002886 @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002887 public static final String LONGITUDE = "longitude";
2888
2889 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002890 * The time the media item was taken.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002891 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002892 @CurrentTimeMillisLong
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002893 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002894 public static final String DATE_TAKEN = "datetaken";
2895
2896 /**
2897 * The mini thumb id.
Jeff Sharkey7049e652018-09-13 17:05:07 -06002898 *
2899 * @deprecated all thumbnails should be obtained via
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06002900 * {@link MediaStore.Images.Thumbnails#getThumbnail}, as this
Jeff Sharkey7049e652018-09-13 17:05:07 -06002901 * value is no longer supported.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002902 */
Jeff Sharkey7049e652018-09-13 17:05:07 -06002903 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002904 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002905 public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
2906
2907 /**
Jeff Sharkey7b148d72019-01-04 14:17:48 -07002908 * The primary bucket ID of this media item. This can be useful to
2909 * present the user a first-level clustering of related media items.
2910 * This is a read-only column that is automatically computed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002911 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002912 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002913 public static final String BUCKET_ID = "bucket_id";
2914
2915 /**
Jeff Sharkey7b148d72019-01-04 14:17:48 -07002916 * The primary bucket display name of this media item. This can be
2917 * useful to present the user a first-level clustering of related
2918 * media items. This is a read-only column that is automatically
2919 * computed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002920 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002921 @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002922 public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
2923
2924 /**
Jeff Sharkeyc4597792019-01-30 15:14:19 -07002925 * The group ID of this media item. This can be useful to present
2926 * the user a grouping of related media items, such a burst of
2927 * images, or a {@code JPG} and {@code DNG} version of the same
2928 * image.
2929 * <p>
2930 * This is a read-only column that is automatically computed based
2931 * on the first portion of the filename. For example,
2932 * {@code IMG1024.BURST001.JPG} and {@code IMG1024.BURST002.JPG}
2933 * will have the same {@link #GROUP_ID} because the first portion of
2934 * their filenames is identical.
Jeff Sharkey7b148d72019-01-04 14:17:48 -07002935 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002936 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
Jeff Sharkeyc4597792019-01-30 15:14:19 -07002937 public static final String GROUP_ID = "group_id";
Jeff Sharkey7b148d72019-01-04 14:17:48 -07002938
2939 /**
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002940 * The position within the video item at which playback should be
2941 * resumed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002942 */
Jeff Sharkey9f05e0e2019-02-18 12:47:25 -07002943 @DurationMillisLong
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002944 @Column(Cursor.FIELD_TYPE_INTEGER)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002945 public static final String BOOKMARK = "bookmark";
nobuhiko saitou839cc002018-09-03 17:26:54 +09002946
2947 /**
2948 * The standard of color aspects
nobuhiko saitou839cc002018-09-03 17:26:54 +09002949 * @hide
2950 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002951 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
nobuhiko saitou839cc002018-09-03 17:26:54 +09002952 public static final String COLOR_STANDARD = "color_standard";
2953
2954 /**
2955 * The transfer of color aspects
nobuhiko saitou839cc002018-09-03 17:26:54 +09002956 * @hide
2957 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002958 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
nobuhiko saitou839cc002018-09-03 17:26:54 +09002959 public static final String COLOR_TRANSFER = "color_transfer";
2960
2961 /**
2962 * The range of color aspects
nobuhiko saitou839cc002018-09-03 17:26:54 +09002963 * @hide
2964 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07002965 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
nobuhiko saitou839cc002018-09-03 17:26:54 +09002966 public static final String COLOR_RANGE = "color_range";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002967 }
2968
2969 public static final class Media implements VideoColumns {
2970 /**
2971 * Get the content:// style URI for the video media table on the
2972 * given volume.
2973 *
2974 * @param volumeName the name of the volume to get the URI for
2975 * @return the URI to the video media table on the given volume
2976 */
2977 public static Uri getContentUri(String volumeName) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06002978 return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("video")
2979 .appendPath("media").build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002980 }
2981
2982 /**
2983 * The content:// style URI for the internal storage.
2984 */
2985 public static final Uri INTERNAL_CONTENT_URI =
2986 getContentUri("internal");
2987
2988 /**
2989 * The content:// style URI for the "primary" external storage
2990 * volume.
2991 */
2992 public static final Uri EXTERNAL_CONTENT_URI =
2993 getContentUri("external");
2994
2995 /**
2996 * The MIME type for this table.
2997 */
2998 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/video";
2999
3000 /**
3001 * The default sort order for this table
3002 */
3003 public static final String DEFAULT_SORT_ORDER = TITLE;
3004 }
Ray Chen00c575a2009-08-28 14:12:15 -07003005
3006 /**
Jeff Sharkey52827962018-10-18 14:44:41 -06003007 * This class provides utility methods to obtain thumbnails for various
3008 * {@link Video} items.
Jeff Sharkey36ee3622019-01-23 10:55:29 -07003009 *
3010 * @deprecated Callers should migrate to using
3011 * {@link ContentResolver#loadThumbnail}, since it offers
3012 * richer control over requested thumbnail sizes and
3013 * cancellation behavior.
Ray Chen00c575a2009-08-28 14:12:15 -07003014 */
Jeff Sharkey36ee3622019-01-23 10:55:29 -07003015 @Deprecated
Ray Chen00c575a2009-08-28 14:12:15 -07003016 public static class Thumbnails implements BaseColumns {
3017 /**
Jeff Sharkey52827962018-10-18 14:44:41 -06003018 * Cancel any outstanding {@link #getThumbnail} requests, causing
3019 * them to return by throwing a {@link OperationCanceledException}.
3020 * <p>
3021 * This method has no effect on
3022 * {@link ContentResolver#loadThumbnail} calls, since they provide
3023 * their own {@link CancellationSignal}.
Ray Chenb9944192009-09-29 20:24:01 -07003024 *
Jeff Sharkey52827962018-10-18 14:44:41 -06003025 * @deprecated Callers should migrate to using
3026 * {@link ContentResolver#loadThumbnail}, since it
3027 * offers richer control over requested thumbnail sizes
3028 * and cancellation behavior.
Ray Chenb9944192009-09-29 20:24:01 -07003029 */
Jeff Sharkey52827962018-10-18 14:44:41 -06003030 @Deprecated
Ray Chenb9944192009-09-29 20:24:01 -07003031 public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06003032 final Uri uri = ContentUris.withAppendedId(
3033 Video.Media.EXTERNAL_CONTENT_URI, origId);
3034 InternalThumbnails.cancelThumbnail(cr, uri);
Ray Chenb9944192009-09-29 20:24:01 -07003035 }
3036
3037 /**
Jeff Sharkey52827962018-10-18 14:44:41 -06003038 * Return thumbnail representing a specific video item. If a
3039 * thumbnail doesn't exist, this method will block until it's
3040 * generated. Callers are responsible for their own in-memory
3041 * caching of returned values.
Ray Chen00c575a2009-08-28 14:12:15 -07003042 *
Jeff Sharkey52827962018-10-18 14:44:41 -06003043 * @param videoId the video item to obtain a thumbnail for.
3044 * @param kind optimal thumbnail size desired.
3045 * @return decoded thumbnail, or {@code null} if problem was
3046 * encountered.
3047 * @deprecated Callers should migrate to using
3048 * {@link ContentResolver#loadThumbnail}, since it
3049 * offers richer control over requested thumbnail sizes
3050 * and cancellation behavior.
Ray Chen13ed5752009-10-05 12:21:24 -07003051 */
Jeff Sharkey52827962018-10-18 14:44:41 -06003052 @Deprecated
3053 public static Bitmap getThumbnail(ContentResolver cr, long videoId, int kind,
Ray Chen13ed5752009-10-05 12:21:24 -07003054 BitmapFactory.Options options) {
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06003055 final Uri uri = ContentUris.withAppendedId(
Jeff Sharkey52827962018-10-18 14:44:41 -06003056 Video.Media.EXTERNAL_CONTENT_URI, videoId);
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06003057 return InternalThumbnails.getThumbnail(cr, uri, kind, options);
Ray Chen13ed5752009-10-05 12:21:24 -07003058 }
3059
3060 /**
Jeff Sharkey52827962018-10-18 14:44:41 -06003061 * Cancel any outstanding {@link #getThumbnail} requests, causing
3062 * them to return by throwing a {@link OperationCanceledException}.
3063 * <p>
3064 * This method has no effect on
3065 * {@link ContentResolver#loadThumbnail} calls, since they provide
3066 * their own {@link CancellationSignal}.
Ray Chen13ed5752009-10-05 12:21:24 -07003067 *
Jeff Sharkey52827962018-10-18 14:44:41 -06003068 * @deprecated Callers should migrate to using
3069 * {@link ContentResolver#loadThumbnail}, since it
3070 * offers richer control over requested thumbnail sizes
3071 * and cancellation behavior.
Ray Chen00c575a2009-08-28 14:12:15 -07003072 */
Jeff Sharkey52827962018-10-18 14:44:41 -06003073 @Deprecated
3074 public static void cancelThumbnailRequest(ContentResolver cr, long videoId,
3075 long groupId) {
3076 cancelThumbnailRequest(cr, videoId);
Ray Chen00c575a2009-08-28 14:12:15 -07003077 }
3078
3079 /**
Jeff Sharkey52827962018-10-18 14:44:41 -06003080 * Return thumbnail representing a specific video item. If a
3081 * thumbnail doesn't exist, this method will block until it's
3082 * generated. Callers are responsible for their own in-memory
3083 * caching of returned values.
Ray Chen13ed5752009-10-05 12:21:24 -07003084 *
Jeff Sharkey52827962018-10-18 14:44:41 -06003085 * @param videoId the video item to obtain a thumbnail for.
3086 * @param kind optimal thumbnail size desired.
3087 * @return decoded thumbnail, or {@code null} if problem was
3088 * encountered.
3089 * @deprecated Callers should migrate to using
3090 * {@link ContentResolver#loadThumbnail}, since it
3091 * offers richer control over requested thumbnail sizes
3092 * and cancellation behavior.
Ray Chen13ed5752009-10-05 12:21:24 -07003093 */
Jeff Sharkey52827962018-10-18 14:44:41 -06003094 @Deprecated
3095 public static Bitmap getThumbnail(ContentResolver cr, long videoId, long groupId,
3096 int kind, BitmapFactory.Options options) {
3097 return getThumbnail(cr, videoId, kind, options);
Ray Chen13ed5752009-10-05 12:21:24 -07003098 }
3099
3100 /**
Ray Chen00c575a2009-08-28 14:12:15 -07003101 * Get the content:// style URI for the image media table on the
3102 * given volume.
3103 *
3104 * @param volumeName the name of the volume to get the URI for
3105 * @return the URI to the image media table on the given volume
3106 */
3107 public static Uri getContentUri(String volumeName) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06003108 return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("video")
3109 .appendPath("thumbnails").build();
Ray Chen00c575a2009-08-28 14:12:15 -07003110 }
3111
3112 /**
3113 * The content:// style URI for the internal storage.
3114 */
3115 public static final Uri INTERNAL_CONTENT_URI =
3116 getContentUri("internal");
3117
3118 /**
3119 * The content:// style URI for the "primary" external storage
3120 * volume.
3121 */
3122 public static final Uri EXTERNAL_CONTENT_URI =
3123 getContentUri("external");
3124
3125 /**
3126 * The default sort order for this table
3127 */
3128 public static final String DEFAULT_SORT_ORDER = "video_id ASC";
3129
3130 /**
Jeff Sharkey60cfad82016-01-05 17:30:57 -07003131 * Path to the thumbnail file on disk.
Jeff Sharkey52827962018-10-18 14:44:41 -06003132 *
3133 * @deprecated Apps may not have filesystem permissions to directly
3134 * access this path. Instead of trying to open this path
3135 * directly, apps should use
3136 * {@link ContentResolver#openFileDescriptor(Uri, String)}
3137 * to gain access. This value will always be
3138 * {@code NULL} for apps targeting
3139 * {@link android.os.Build.VERSION_CODES#Q} or higher.
Ray Chen00c575a2009-08-28 14:12:15 -07003140 */
Jeff Sharkey52827962018-10-18 14:44:41 -06003141 @Deprecated
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07003142 @Column(Cursor.FIELD_TYPE_STRING)
Ray Chen00c575a2009-08-28 14:12:15 -07003143 public static final String DATA = "_data";
3144
3145 /**
3146 * The original image for the thumbnal
Ray Chen00c575a2009-08-28 14:12:15 -07003147 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07003148 @Column(Cursor.FIELD_TYPE_INTEGER)
Ray Chen00c575a2009-08-28 14:12:15 -07003149 public static final String VIDEO_ID = "video_id";
3150
3151 /**
3152 * The kind of the thumbnail
Ray Chen00c575a2009-08-28 14:12:15 -07003153 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07003154 @Column(Cursor.FIELD_TYPE_INTEGER)
Ray Chen00c575a2009-08-28 14:12:15 -07003155 public static final String KIND = "kind";
3156
Jeff Sharkey30b77bc2018-07-27 20:56:34 -06003157 public static final int MINI_KIND = ThumbnailConstants.MINI_KIND;
3158 public static final int FULL_SCREEN_KIND = ThumbnailConstants.FULL_SCREEN_KIND;
3159 public static final int MICRO_KIND = ThumbnailConstants.MICRO_KIND;
Ray Chen00c575a2009-08-28 14:12:15 -07003160
3161 /**
3162 * The width of the thumbnal
Ray Chen00c575a2009-08-28 14:12:15 -07003163 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07003164 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
Ray Chen00c575a2009-08-28 14:12:15 -07003165 public static final String WIDTH = "width";
3166
3167 /**
3168 * The height of the thumbnail
Ray Chen00c575a2009-08-28 14:12:15 -07003169 */
Jeff Sharkey9c41bda2019-02-14 15:29:37 -07003170 @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
Ray Chen00c575a2009-08-28 14:12:15 -07003171 public static final String HEIGHT = "height";
3172 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003173 }
3174
3175 /**
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06003176 * Return list of all volume names currently available. This includes a
3177 * unique name for each shared storage device that is currently mounted.
3178 * <p>
3179 * Each name can be passed to APIs like
3180 * {@link MediaStore.Images.Media#getContentUri(String)} to query media at
3181 * that location.
3182 */
3183 public static @NonNull Set<String> getAllVolumeNames(Context context) {
3184 final StorageManager sm = context.getSystemService(StorageManager.class);
3185 final Set<String> volumeNames = new ArraySet<>();
3186 volumeNames.add(VOLUME_INTERNAL);
3187 for (VolumeInfo vi : sm.getVolumes()) {
Jeff Sharkey30360892019-01-20 13:14:21 -07003188 if (vi.isVisibleForUser(UserHandle.myUserId()) && vi.isMountedReadable()) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06003189 if (vi.isPrimary()) {
3190 volumeNames.add(VOLUME_EXTERNAL);
3191 } else {
Jeff Sharkey3f64ec52019-01-22 13:19:40 -07003192 volumeNames.add(vi.getNormalizedFsUuid());
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06003193 }
3194 }
3195 }
3196 return volumeNames;
3197 }
3198
3199 /**
Jeff Sharkeybc2ae002018-07-31 10:45:37 -06003200 * Return the volume name that the given {@link Uri} references.
3201 */
3202 public static @NonNull String getVolumeName(@NonNull Uri uri) {
3203 final List<String> segments = uri.getPathSegments();
3204 if (uri.getAuthority().equals(AUTHORITY) && segments != null && segments.size() > 0) {
3205 return segments.get(0);
3206 } else {
Jeff Sharkey8559e652019-01-20 11:21:59 -07003207 throw new IllegalArgumentException("Missing volume name: " + uri);
Jeff Sharkeybc2ae002018-07-31 10:45:37 -06003208 }
3209 }
3210
Jeff Sharkeyc8e49242018-11-02 14:34:44 -06003211 /** {@hide} */
Jeff Sharkey8559e652019-01-20 11:21:59 -07003212 public static @NonNull String checkArgumentVolumeName(@NonNull String volumeName) {
3213 if (TextUtils.isEmpty(volumeName)) {
3214 throw new IllegalArgumentException();
3215 }
3216
3217 if (VOLUME_INTERNAL.equals(volumeName)) {
3218 return volumeName;
3219 } else if (VOLUME_EXTERNAL.equals(volumeName)) {
3220 return volumeName;
3221 }
3222
3223 // When not one of the well-known values above, it must be a hex UUID
3224 for (int i = 0; i < volumeName.length(); i++) {
3225 final char c = volumeName.charAt(i);
Jeff Sharkey3f64ec52019-01-22 13:19:40 -07003226 if (('a' <= c && c <= 'f') || ('0' <= c && c <= '9') || (c == '-')) {
Jeff Sharkey8559e652019-01-20 11:21:59 -07003227 continue;
3228 } else {
3229 throw new IllegalArgumentException("Invalid volume name: " + volumeName);
3230 }
3231 }
3232 return volumeName;
3233 }
3234
Jeff Sharkey3f64ec52019-01-22 13:19:40 -07003235 /**
3236 * Return path where the given volume is mounted. Not valid for
3237 * {@link #VOLUME_INTERNAL}.
3238 *
3239 * @hide
3240 */
Jeff Sharkeycb269aac2019-01-25 11:15:38 -07003241 @TestApi
Jeff Sharkeyc8e49242018-11-02 14:34:44 -06003242 public static @NonNull File getVolumePath(@NonNull String volumeName)
3243 throws FileNotFoundException {
Jeff Sharkey8559e652019-01-20 11:21:59 -07003244 if (TextUtils.isEmpty(volumeName)) {
3245 throw new IllegalArgumentException();
3246 }
Jeff Sharkeyc8e49242018-11-02 14:34:44 -06003247
Jeff Sharkey3f64ec52019-01-22 13:19:40 -07003248 if (VOLUME_EXTERNAL.equals(volumeName)) {
Jeff Sharkeyc8e49242018-11-02 14:34:44 -06003249 return Environment.getExternalStorageDirectory();
3250 }
3251
3252 final StorageManager sm = AppGlobals.getInitialApplication()
3253 .getSystemService(StorageManager.class);
3254 for (VolumeInfo vi : sm.getVolumes()) {
Jeff Sharkey3f64ec52019-01-22 13:19:40 -07003255 if (Objects.equals(vi.getNormalizedFsUuid(), volumeName)) {
Jeff Sharkeyc8e49242018-11-02 14:34:44 -06003256 final File path = vi.getPathForUser(UserHandle.myUserId());
Jeff Sharkeyf81494a2019-01-19 13:26:07 -07003257 if (path != null) {
3258 return path;
3259 } else {
Jeff Sharkeyc8e49242018-11-02 14:34:44 -06003260 throw new FileNotFoundException("Failed to find path for " + vi);
3261 }
3262 }
3263 }
3264 throw new FileNotFoundException("Failed to find path for " + volumeName);
3265 }
3266
Jeff Sharkeybc2ae002018-07-31 10:45:37 -06003267 /**
Jeff Sharkey3f64ec52019-01-22 13:19:40 -07003268 * Return paths that should be scanned for the given volume.
3269 *
3270 * @hide
3271 */
Jeff Sharkeycb269aac2019-01-25 11:15:38 -07003272 @TestApi
Jeff Sharkey3f64ec52019-01-22 13:19:40 -07003273 public static @NonNull Collection<File> getVolumeScanPaths(@NonNull String volumeName)
3274 throws FileNotFoundException {
3275 if (TextUtils.isEmpty(volumeName)) {
3276 throw new IllegalArgumentException();
3277 }
3278
3279 final ArrayList<File> res = new ArrayList<>();
3280 if (VOLUME_INTERNAL.equals(volumeName)) {
Jeff Sharkey858b3112019-02-08 14:38:59 -07003281 addCanoncialFile(res, new File(Environment.getRootDirectory(), "media"));
3282 addCanoncialFile(res, new File(Environment.getOemDirectory(), "media"));
3283 addCanoncialFile(res, new File(Environment.getProductDirectory(), "media"));
Jeff Sharkey3f64ec52019-01-22 13:19:40 -07003284 } else {
Jeff Sharkey858b3112019-02-08 14:38:59 -07003285 addCanoncialFile(res, getVolumePath(volumeName));
Jeff Sharkey3f64ec52019-01-22 13:19:40 -07003286 final UserManager um = AppGlobals.getInitialApplication()
3287 .getSystemService(UserManager.class);
3288 if (VOLUME_EXTERNAL.equals(volumeName) && um.isDemoUser()) {
Jeff Sharkey858b3112019-02-08 14:38:59 -07003289 addCanoncialFile(res, Environment.getDataPreloadsMediaDirectory());
Jeff Sharkey3f64ec52019-01-22 13:19:40 -07003290 }
3291 }
3292 return res;
3293 }
3294
Jeff Sharkey858b3112019-02-08 14:38:59 -07003295 private static void addCanoncialFile(List<File> list, File file) {
3296 try {
3297 list.add(file.getCanonicalFile());
3298 } catch (IOException e) {
3299 Log.w(TAG, "Failed to resolve " + file + ": " + e);
3300 list.add(file);
3301 }
3302 }
3303
Jeff Sharkey3f64ec52019-01-22 13:19:40 -07003304 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003305 * Uri for querying the state of the media scanner.
3306 */
3307 public static Uri getMediaScannerUri() {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06003308 return AUTHORITY_URI.buildUpon().appendPath("none").appendPath("media_scanner").build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309 }
3310
3311 /**
3312 * Name of current volume being scanned by the media scanner.
3313 */
3314 public static final String MEDIA_SCANNER_VOLUME = "volume";
Karl Ostmo8ce072d2010-01-30 15:15:39 -06003315
3316 /**
3317 * Name of the file signaling the media scanner to ignore media in the containing directory
3318 * and its subdirectories. Developers should use this to avoid application graphics showing
3319 * up in the Gallery and likewise prevent application sounds and music from showing up in
3320 * the Music app.
3321 */
3322 public static final String MEDIA_IGNORE_FILENAME = ".nomedia";
Marco Nelissen3822f732011-02-03 10:59:30 -08003323
3324 /**
3325 * Get the media provider's version.
3326 * Applications that import data from the media provider into their own caches
3327 * can use this to detect that the media provider changed, and reimport data
3328 * as needed. No other assumptions should be made about the meaning of the version.
3329 * @param context Context to use for performing the query.
3330 * @return A version string, or null if the version could not be determined.
Marco Nelissen3822f732011-02-03 10:59:30 -08003331 */
3332 public static String getVersion(Context context) {
Jeff Sharkey0fc74ab2018-10-30 19:16:29 -06003333 final Uri uri = AUTHORITY_URI.buildUpon().appendPath("none").appendPath("version").build();
3334 try (Cursor c = context.getContentResolver().query(uri, null, null, null, null)) {
3335 if (c.moveToFirst()) {
3336 return c.getString(0);
Marco Nelissen3822f732011-02-03 10:59:30 -08003337 }
3338 }
3339 return null;
3340 }
Garfield Tan92b96ba2016-11-01 14:33:48 -07003341
3342 /**
Jeff Sharkey643e99e2018-10-22 18:01:27 -06003343 * Return a {@link DocumentsProvider} Uri that is an equivalent to the given
3344 * {@link MediaStore} Uri.
Garfield Tan92b96ba2016-11-01 14:33:48 -07003345 * <p>
Jeff Sharkey643e99e2018-10-22 18:01:27 -06003346 * This allows apps with Storage Access Framework permissions to convert
3347 * between {@link MediaStore} and {@link DocumentsProvider} Uris that refer
3348 * to the same underlying item. Note that this method doesn't grant any new
3349 * permissions; callers must already hold permissions obtained with
3350 * {@link Intent#ACTION_OPEN_DOCUMENT} or related APIs.
Garfield Tan92b96ba2016-11-01 14:33:48 -07003351 *
Jeff Sharkey643e99e2018-10-22 18:01:27 -06003352 * @param mediaUri The {@link MediaStore} Uri to convert.
3353 * @return An equivalent {@link DocumentsProvider} Uri. Returns {@code null}
3354 * if no equivalent was found.
3355 * @see #getMediaUri(Context, Uri)
Garfield Tan92b96ba2016-11-01 14:33:48 -07003356 */
3357 public static Uri getDocumentUri(Context context, Uri mediaUri) {
Jeff Sharkey643e99e2018-10-22 18:01:27 -06003358 final ContentResolver resolver = context.getContentResolver();
3359 final List<UriPermission> uriPermissions = resolver.getPersistedUriPermissions();
Garfield Tan92b96ba2016-11-01 14:33:48 -07003360
Jeff Sharkey643e99e2018-10-22 18:01:27 -06003361 try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
3362 final Bundle in = new Bundle();
3363 in.putParcelable(DocumentsContract.EXTRA_URI, mediaUri);
3364 in.putParcelableList(DocumentsContract.EXTRA_URI_PERMISSIONS, uriPermissions);
3365 final Bundle out = client.call(GET_DOCUMENT_URI_CALL, null, in);
3366 return out.getParcelable(DocumentsContract.EXTRA_URI);
Garfield Tan92b96ba2016-11-01 14:33:48 -07003367 } catch (RemoteException e) {
3368 throw e.rethrowAsRuntimeException();
3369 }
3370 }
3371
Jeff Sharkey643e99e2018-10-22 18:01:27 -06003372 /**
3373 * Return a {@link MediaStore} Uri that is an equivalent to the given
3374 * {@link DocumentsProvider} Uri.
3375 * <p>
3376 * This allows apps with Storage Access Framework permissions to convert
3377 * between {@link MediaStore} and {@link DocumentsProvider} Uris that refer
3378 * to the same underlying item. Note that this method doesn't grant any new
3379 * permissions; callers must already hold permissions obtained with
3380 * {@link Intent#ACTION_OPEN_DOCUMENT} or related APIs.
3381 *
3382 * @param documentUri The {@link DocumentsProvider} Uri to convert.
3383 * @return An equivalent {@link MediaStore} Uri. Returns {@code null} if no
3384 * equivalent was found.
3385 * @see #getDocumentUri(Context, Uri)
3386 */
3387 public static Uri getMediaUri(Context context, Uri documentUri) {
3388 final ContentResolver resolver = context.getContentResolver();
3389 final List<UriPermission> uriPermissions = resolver.getPersistedUriPermissions();
Garfield Tan92b96ba2016-11-01 14:33:48 -07003390
Jeff Sharkey643e99e2018-10-22 18:01:27 -06003391 try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) {
Garfield Tan92b96ba2016-11-01 14:33:48 -07003392 final Bundle in = new Bundle();
Jeff Sharkey643e99e2018-10-22 18:01:27 -06003393 in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
3394 in.putParcelableList(DocumentsContract.EXTRA_URI_PERMISSIONS, uriPermissions);
3395 final Bundle out = client.call(GET_MEDIA_URI_CALL, null, in);
Garfield Tan92b96ba2016-11-01 14:33:48 -07003396 return out.getParcelable(DocumentsContract.EXTRA_URI);
Jeff Sharkey643e99e2018-10-22 18:01:27 -06003397 } catch (RemoteException e) {
3398 throw e.rethrowAsRuntimeException();
Garfield Tan92b96ba2016-11-01 14:33:48 -07003399 }
3400 }
Jeff Sharkey9efa7b82018-12-07 17:15:36 -07003401
3402 /**
3403 * Calculate size of media contributed by given package under the calling
3404 * user. The meaning of "contributed" means it won't automatically be
3405 * deleted when the app is uninstalled.
3406 *
3407 * @hide
3408 */
Jeff Sharkey9efa7b82018-12-07 17:15:36 -07003409 @TestApi
3410 @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA)
Jeff Sharkeydc50d4c2018-12-10 18:28:56 -07003411 public static @BytesLong long getContributedMediaSize(Context context, String packageName,
3412 UserHandle user) throws IOException {
3413 final UserManager um = context.getSystemService(UserManager.class);
3414 if (um.isUserUnlocked(user) && um.isUserRunning(user)) {
3415 try {
3416 final ContentResolver resolver = context
3417 .createPackageContextAsUser(packageName, 0, user).getContentResolver();
3418 final Bundle in = new Bundle();
3419 in.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
3420 final Bundle out = resolver.call(AUTHORITY, GET_CONTRIBUTED_MEDIA_CALL, null, in);
3421 return out.getLong(Intent.EXTRA_INDEX);
3422 } catch (Exception e) {
3423 throw new IOException(e);
3424 }
3425 } else {
3426 throw new IOException("User " + user + " must be unlocked and running");
Jeff Sharkey9efa7b82018-12-07 17:15:36 -07003427 }
3428 }
3429
3430 /**
3431 * Delete all media contributed by given package under the calling user. The
3432 * meaning of "contributed" means it won't automatically be deleted when the
3433 * app is uninstalled.
3434 *
3435 * @hide
3436 */
Jeff Sharkey9efa7b82018-12-07 17:15:36 -07003437 @TestApi
3438 @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA)
Jeff Sharkeydc50d4c2018-12-10 18:28:56 -07003439 public static void deleteContributedMedia(Context context, String packageName,
3440 UserHandle user) throws IOException {
3441 final UserManager um = context.getSystemService(UserManager.class);
3442 if (um.isUserUnlocked(user) && um.isUserRunning(user)) {
3443 try {
3444 final ContentResolver resolver = context
3445 .createPackageContextAsUser(packageName, 0, user).getContentResolver();
3446 final Bundle in = new Bundle();
3447 in.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
3448 resolver.call(AUTHORITY, DELETE_CONTRIBUTED_MEDIA_CALL, null, in);
3449 } catch (Exception e) {
3450 throw new IOException(e);
3451 }
3452 } else {
3453 throw new IOException("User " + user + " must be unlocked and running");
Jeff Sharkey9efa7b82018-12-07 17:15:36 -07003454 }
3455 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003456}