1e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey/* 2e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey * Copyright (C) 2013 The Android Open Source Project 3e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey * 4e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 5e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey * you may not use this file except in compliance with the License. 6e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey * You may obtain a copy of the License at 7e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey * 8e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 9e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey * 10e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey * Unless required by applicable law or agreed to in writing, software 11e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 12e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey * See the License for the specific language governing permissions and 14e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey * limitations under the License. 15e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey */ 16e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 17e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeypackage com.android.providers.media; 18e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 19e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.content.ContentResolver; 20e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.content.ContentUris; 21ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkeyimport android.content.Context; 22240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkeyimport android.content.res.AssetFileDescriptor; 23e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.database.Cursor; 24e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.database.MatrixCursor; 25e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.database.MatrixCursor.RowBuilder; 260f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkeyimport android.graphics.BitmapFactory; 276e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkeyimport android.graphics.Point; 28e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.net.Uri; 29e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.os.Binder; 305082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkeyimport android.os.Bundle; 316e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkeyimport android.os.CancellationSignal; 32e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.os.ParcelFileDescriptor; 33e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.provider.BaseColumns; 34e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.provider.DocumentsContract; 35498075b5efbc333e462104a83b95c12bd842223eJeff Sharkeyimport android.provider.DocumentsContract.Document; 36498075b5efbc333e462104a83b95c12bd842223eJeff Sharkeyimport android.provider.DocumentsContract.Root; 376e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkeyimport android.provider.DocumentsProvider; 38e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.provider.MediaStore.Audio; 39e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.provider.MediaStore.Audio.AlbumColumns; 40e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.provider.MediaStore.Audio.Albums; 41e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.provider.MediaStore.Audio.ArtistColumns; 42e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.provider.MediaStore.Audio.Artists; 43e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.provider.MediaStore.Audio.AudioColumns; 44b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkeyimport android.provider.MediaStore.Files.FileColumns; 45e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.provider.MediaStore.Images; 46e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.provider.MediaStore.Images.ImageColumns; 470f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkeyimport android.provider.MediaStore.Video; 480f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkeyimport android.provider.MediaStore.Video.VideoColumns; 496718b71ef44d06a70eeb0ea9ce66140ecdcafdbbJeff Sharkeyimport android.text.TextUtils; 50e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport android.text.format.DateUtils; 515082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkeyimport android.util.Log; 52e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 53e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport libcore.io.IoUtils; 54e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 550f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkeyimport java.io.File; 56e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkeyimport java.io.FileNotFoundException; 57e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 58e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey/** 59b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey * Presents a {@link DocumentsContract} view of {@link MediaProvider} external 60b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey * contents. 61e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey */ 626e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkeypublic class MediaDocumentsProvider extends DocumentsProvider { 635082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey private static final String TAG = "MediaDocumentsProvider"; 646e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey 65b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey private static final String AUTHORITY = "com.android.providers.media.documents"; 66b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey 67498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey private static final String[] DEFAULT_ROOT_PROJECTION = new String[] { 684cb8114276183402558ede05ab92ee8f7a996a34Jeff Sharkey Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON, 694cb8114276183402558ede05ab92ee8f7a996a34Jeff Sharkey Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID, Root.COLUMN_MIME_TYPES 70498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey }; 71498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey 72498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] { 73498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME, 74498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE, 756e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey }; 766e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey 776718b71ef44d06a70eeb0ea9ce66140ecdcafdbbJeff Sharkey private static final String IMAGE_MIME_TYPES = joinNewline("image/*"); 786718b71ef44d06a70eeb0ea9ce66140ecdcafdbbJeff Sharkey 790f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private static final String VIDEO_MIME_TYPES = joinNewline("video/*"); 800f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 816718b71ef44d06a70eeb0ea9ce66140ecdcafdbbJeff Sharkey private static final String AUDIO_MIME_TYPES = joinNewline( 826718b71ef44d06a70eeb0ea9ce66140ecdcafdbbJeff Sharkey "audio/*", "application/ogg", "application/x-flac"); 836718b71ef44d06a70eeb0ea9ce66140ecdcafdbbJeff Sharkey 840f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private static final String TYPE_IMAGES_ROOT = "images_root"; 850f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private static final String TYPE_IMAGES_BUCKET = "images_bucket"; 866e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey private static final String TYPE_IMAGE = "image"; 87e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 880f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private static final String TYPE_VIDEOS_ROOT = "videos_root"; 890f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private static final String TYPE_VIDEOS_BUCKET = "videos_bucket"; 900f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private static final String TYPE_VIDEO = "video"; 910f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 920f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private static final String TYPE_AUDIO_ROOT = "audio_root"; 936e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey private static final String TYPE_AUDIO = "audio"; 946e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey private static final String TYPE_ARTIST = "artist"; 956e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey private static final String TYPE_ALBUM = "album"; 96e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 97ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey private static boolean sReturnedImagesEmpty = false; 98ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey private static boolean sReturnedVideosEmpty = false; 99ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey private static boolean sReturnedAudioEmpty = false; 100ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey 1016718b71ef44d06a70eeb0ea9ce66140ecdcafdbbJeff Sharkey private static String joinNewline(String... args) { 1026718b71ef44d06a70eeb0ea9ce66140ecdcafdbbJeff Sharkey return TextUtils.join("\n", args); 1036718b71ef44d06a70eeb0ea9ce66140ecdcafdbbJeff Sharkey } 1046718b71ef44d06a70eeb0ea9ce66140ecdcafdbbJeff Sharkey 105f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey private void copyNotificationUri(MatrixCursor result, Cursor cursor) { 106f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey result.setNotificationUri(getContext().getContentResolver(), cursor.getNotificationUri()); 107f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey } 108f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey 1096e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey @Override 1106e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey public boolean onCreate() { 1116e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey return true; 112e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 113e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 114ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey private static void notifyRootsChanged(Context context) { 115b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey context.getContentResolver() 116b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey .notifyChange(DocumentsContract.buildRootsUri(AUTHORITY), null, false); 117ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey } 118ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey 119b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey /** 120b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey * When inserting the first item of each type, we need to trigger a roots 121b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey * refresh to clear a previously reported {@link Root#FLAG_EMPTY}. 122b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey */ 123b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey static void onMediaStoreInsert(Context context, String volumeName, int type, long id) { 124b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey if (!"external".equals(volumeName)) return; 125ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey 126b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey if (type == FileColumns.MEDIA_TYPE_IMAGE && sReturnedImagesEmpty) { 127b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey sReturnedImagesEmpty = false; 128ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey notifyRootsChanged(context); 129b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey } else if (type == FileColumns.MEDIA_TYPE_VIDEO && sReturnedVideosEmpty) { 130ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey sReturnedVideosEmpty = false; 131b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey notifyRootsChanged(context); 132b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey } else if (type == FileColumns.MEDIA_TYPE_AUDIO && sReturnedAudioEmpty) { 133b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey sReturnedAudioEmpty = false; 134b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey notifyRootsChanged(context); 135ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey } 136ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey } 137ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey 138b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey /** 139b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey * When deleting an item, we need to revoke any outstanding Uri grants. 140b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey */ 141b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey static void onMediaStoreDelete(Context context, String volumeName, int type, long id) { 142b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey if (!"external".equals(volumeName)) return; 143b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey 144b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey if (type == FileColumns.MEDIA_TYPE_IMAGE) { 145b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey final Uri uri = DocumentsContract.buildDocumentUri( 146b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey AUTHORITY, getDocIdForIdent(TYPE_IMAGE, id)); 147b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey context.revokeUriPermission(uri, ~0); 148b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey } else if (type == FileColumns.MEDIA_TYPE_VIDEO) { 149b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey final Uri uri = DocumentsContract.buildDocumentUri( 150b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey AUTHORITY, getDocIdForIdent(TYPE_VIDEO, id)); 151b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey context.revokeUriPermission(uri, ~0); 152b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey } else if (type == FileColumns.MEDIA_TYPE_AUDIO) { 153b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey final Uri uri = DocumentsContract.buildDocumentUri( 154b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey AUTHORITY, getDocIdForIdent(TYPE_AUDIO, id)); 155b39b32d96e938d5a5792bb56e4c37f3e752493cdJeff Sharkey context.revokeUriPermission(uri, ~0); 156ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey } 157ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey } 158ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey 1596e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey private static class Ident { 1606e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey public String type; 1616e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey public long id; 1626e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 163e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 1646e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey private static Ident getIdentForDocId(String docId) { 1656e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final Ident ident = new Ident(); 1666e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final int split = docId.indexOf(':'); 1676e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey if (split == -1) { 1686e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey ident.type = docId; 1696e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey ident.id = -1; 1706e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } else { 1716e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey ident.type = docId.substring(0, split); 1726e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey ident.id = Long.parseLong(docId.substring(split + 1)); 1736e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 1746e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey return ident; 1756e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 1766e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey 1776e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey private static String getDocIdForIdent(String type, long id) { 1786e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey return type + ":" + id; 1796e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 180e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 181498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey private static String[] resolveRootProjection(String[] projection) { 182498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey return projection != null ? projection : DEFAULT_ROOT_PROJECTION; 183498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey } 184498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey 185498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey private static String[] resolveDocumentProjection(String[] projection) { 186498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION; 187498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey } 188498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey 189e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey @Override 190498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey public Cursor queryRoots(String[] projection) throws FileNotFoundException { 191498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection)); 192498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey includeImagesRoot(result); 1930f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey includeVideosRoot(result); 194498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey includeAudioRoot(result); 195498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey return result; 196e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 197e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 198e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey @Override 199498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey public Cursor queryDocument(String docId, String[] projection) throws FileNotFoundException { 200e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final ContentResolver resolver = getContext().getContentResolver(); 201498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); 2026e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final Ident ident = getIdentForDocId(docId); 2036e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey 2046e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final long token = Binder.clearCallingIdentity(); 2056e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey Cursor cursor = null; 2066e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey try { 2070f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (TYPE_IMAGES_ROOT.equals(ident.type)) { 2086e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey // single root 2090f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey includeImagesRootDocument(result); 2100f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_IMAGES_BUCKET.equals(ident.type)) { 2116e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey // single bucket 2126e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey cursor = resolver.query(Images.Media.EXTERNAL_CONTENT_URI, 2130f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey ImagesBucketQuery.PROJECTION, ImageColumns.BUCKET_ID + "=" + ident.id, 2144c9dda96c93853561519de9934167ff337e3b281Jeff Sharkey null, ImagesBucketQuery.SORT_ORDER); 215f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey copyNotificationUri(result, cursor); 2166e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey if (cursor.moveToFirst()) { 2170f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey includeImagesBucket(result, cursor); 218e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 2196e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } else if (TYPE_IMAGE.equals(ident.type)) { 2206e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey // single image 2216e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey cursor = resolver.query(Images.Media.EXTERNAL_CONTENT_URI, 2226e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey ImageQuery.PROJECTION, BaseColumns._ID + "=" + ident.id, null, 2236e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey null); 224f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey copyNotificationUri(result, cursor); 2256e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey if (cursor.moveToFirst()) { 2266e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey includeImage(result, cursor); 227e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 2280f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_VIDEOS_ROOT.equals(ident.type)) { 2296e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey // single root 2300f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey includeVideosRootDocument(result); 2310f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_VIDEOS_BUCKET.equals(ident.type)) { 2320f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey // single bucket 2330f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor = resolver.query(Video.Media.EXTERNAL_CONTENT_URI, 2340f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideosBucketQuery.PROJECTION, VideoColumns.BUCKET_ID + "=" + ident.id, 2354c9dda96c93853561519de9934167ff337e3b281Jeff Sharkey null, VideosBucketQuery.SORT_ORDER); 2360f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey copyNotificationUri(result, cursor); 2370f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (cursor.moveToFirst()) { 238c5341234fb73d7f53a817a563466a0ea76850529Jeff Sharkey includeVideosBucket(result, cursor); 2390f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 2400f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_VIDEO.equals(ident.type)) { 2410f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey // single video 2420f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor = resolver.query(Video.Media.EXTERNAL_CONTENT_URI, 2430f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoQuery.PROJECTION, BaseColumns._ID + "=" + ident.id, null, 2440f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey null); 2450f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey copyNotificationUri(result, cursor); 2460f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (cursor.moveToFirst()) { 2470f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey includeVideo(result, cursor); 2480f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 2490f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_AUDIO_ROOT.equals(ident.type)) { 2500f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey // single root 2510f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey includeAudioRootDocument(result); 2526e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } else if (TYPE_ARTIST.equals(ident.type)) { 2536e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey // single artist 2546e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey cursor = resolver.query(Artists.EXTERNAL_CONTENT_URI, 2556e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey ArtistQuery.PROJECTION, BaseColumns._ID + "=" + ident.id, null, 2566e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey null); 257f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey copyNotificationUri(result, cursor); 2586e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey if (cursor.moveToFirst()) { 2596e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey includeArtist(result, cursor); 2606e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 2616e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } else if (TYPE_ALBUM.equals(ident.type)) { 2626e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey // single album 2636e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey cursor = resolver.query(Albums.EXTERNAL_CONTENT_URI, 2646e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey AlbumQuery.PROJECTION, BaseColumns._ID + "=" + ident.id, null, 2656e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey null); 266f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey copyNotificationUri(result, cursor); 2676e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey if (cursor.moveToFirst()) { 2686e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey includeAlbum(result, cursor); 2696e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 2706e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } else if (TYPE_AUDIO.equals(ident.type)) { 2716e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey // single song 2726e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey cursor = resolver.query(Audio.Media.EXTERNAL_CONTENT_URI, 2736e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey SongQuery.PROJECTION, BaseColumns._ID + "=" + ident.id, null, 2746e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey null); 275f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey copyNotificationUri(result, cursor); 2766e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey if (cursor.moveToFirst()) { 2776e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey includeAudio(result, cursor); 2786e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 2796e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } else { 2806e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey throw new UnsupportedOperationException("Unsupported document " + docId); 281e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 2826e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } finally { 2836e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey IoUtils.closeQuietly(cursor); 2846e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey Binder.restoreCallingIdentity(token); 2856e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 2866e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey return result; 2876e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 2886e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey 2896e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey @Override 290498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey public Cursor queryChildDocuments(String docId, String[] projection, String sortOrder) 291498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey throws FileNotFoundException { 2926e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final ContentResolver resolver = getContext().getContentResolver(); 293498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); 2946e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final Ident ident = getIdentForDocId(docId); 2956e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey 2966e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final long token = Binder.clearCallingIdentity(); 2976e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey Cursor cursor = null; 2986e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey try { 2990f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (TYPE_IMAGES_ROOT.equals(ident.type)) { 3006e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey // include all unique buckets 3016e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey cursor = resolver.query(Images.Media.EXTERNAL_CONTENT_URI, 3024c9dda96c93853561519de9934167ff337e3b281Jeff Sharkey ImagesBucketQuery.PROJECTION, null, null, ImagesBucketQuery.SORT_ORDER); 3034c9dda96c93853561519de9934167ff337e3b281Jeff Sharkey // multiple orders 304f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey copyNotificationUri(result, cursor); 3056e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey long lastId = Long.MIN_VALUE; 3066e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey while (cursor.moveToNext()) { 3070f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final long id = cursor.getLong(ImagesBucketQuery.BUCKET_ID); 3086e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey if (lastId != id) { 3090f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey includeImagesBucket(result, cursor); 3106e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey lastId = id; 311e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 312e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 3130f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_IMAGES_BUCKET.equals(ident.type)) { 3146e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey // include images under bucket 3156e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey cursor = resolver.query(Images.Media.EXTERNAL_CONTENT_URI, 3166e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey ImageQuery.PROJECTION, ImageColumns.BUCKET_ID + "=" + ident.id, 3176e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey null, null); 318f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey copyNotificationUri(result, cursor); 3196e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey while (cursor.moveToNext()) { 3206e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey includeImage(result, cursor); 3216e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 3220f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_VIDEOS_ROOT.equals(ident.type)) { 3230f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey // include all unique buckets 3240f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor = resolver.query(Video.Media.EXTERNAL_CONTENT_URI, 3254c9dda96c93853561519de9934167ff337e3b281Jeff Sharkey VideosBucketQuery.PROJECTION, null, null, VideosBucketQuery.SORT_ORDER); 3260f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey copyNotificationUri(result, cursor); 3270f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey long lastId = Long.MIN_VALUE; 3280f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey while (cursor.moveToNext()) { 3290f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final long id = cursor.getLong(VideosBucketQuery.BUCKET_ID); 3300f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (lastId != id) { 3310f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey includeVideosBucket(result, cursor); 3320f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey lastId = id; 3330f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 3340f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 3350f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_VIDEOS_BUCKET.equals(ident.type)) { 3360f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey // include videos under bucket 3370f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor = resolver.query(Video.Media.EXTERNAL_CONTENT_URI, 3380f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoQuery.PROJECTION, VideoColumns.BUCKET_ID + "=" + ident.id, 3390f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey null, null); 3400f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey copyNotificationUri(result, cursor); 3410f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey while (cursor.moveToNext()) { 3420f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey includeVideo(result, cursor); 3430f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 3440f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_AUDIO_ROOT.equals(ident.type)) { 3456e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey // include all artists 3466e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey cursor = resolver.query(Audio.Artists.EXTERNAL_CONTENT_URI, 3476e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey ArtistQuery.PROJECTION, null, null, null); 348f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey copyNotificationUri(result, cursor); 3496e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey while (cursor.moveToNext()) { 3506e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey includeArtist(result, cursor); 3516e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 3526e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } else if (TYPE_ARTIST.equals(ident.type)) { 3536e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey // include all albums under artist 3546e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey cursor = resolver.query(Artists.Albums.getContentUri("external", ident.id), 3556e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey AlbumQuery.PROJECTION, null, null, null); 356f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey copyNotificationUri(result, cursor); 3576e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey while (cursor.moveToNext()) { 3586e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey includeAlbum(result, cursor); 3596e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 3606e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } else if (TYPE_ALBUM.equals(ident.type)) { 3616e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey // include all songs under album 3626e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey cursor = resolver.query(Audio.Media.EXTERNAL_CONTENT_URI, 3636e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey SongQuery.PROJECTION, AudioColumns.ALBUM_ID + "=" + ident.id, 3646e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey null, null); 365f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey copyNotificationUri(result, cursor); 3666e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey while (cursor.moveToNext()) { 3676e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey includeAudio(result, cursor); 3686e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 3696e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } else { 3706e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey throw new UnsupportedOperationException("Unsupported document " + docId); 371e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 3726e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } finally { 3736e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey IoUtils.closeQuietly(cursor); 3746e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey Binder.restoreCallingIdentity(token); 375e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 3766e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey return result; 377e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 378e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 3796e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey @Override 3803c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey public Cursor queryRecentDocuments(String rootId, String[] projection) 3813c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey throws FileNotFoundException { 3823c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey final ContentResolver resolver = getContext().getContentResolver(); 3833c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); 3843c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey 3853c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey final long token = Binder.clearCallingIdentity(); 3863c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey Cursor cursor = null; 3873c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey try { 3880f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (TYPE_IMAGES_ROOT.equals(rootId)) { 3893c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey // include all unique buckets 3903c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey cursor = resolver.query(Images.Media.EXTERNAL_CONTENT_URI, 3913c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey ImageQuery.PROJECTION, null, null, ImageColumns.DATE_MODIFIED + " DESC"); 392f9de3a3dd5bbc0251672b33ca12c0f0306556e62Jeff Sharkey copyNotificationUri(result, cursor); 3930f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey while (cursor.moveToNext() && result.getCount() < 64) { 3943c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey includeImage(result, cursor); 3953c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey } 3960f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_VIDEOS_ROOT.equals(rootId)) { 3970f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey // include all unique buckets 3980f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor = resolver.query(Video.Media.EXTERNAL_CONTENT_URI, 3990f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoQuery.PROJECTION, null, null, VideoColumns.DATE_MODIFIED + " DESC"); 4000f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey copyNotificationUri(result, cursor); 4010f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey while (cursor.moveToNext() && result.getCount() < 64) { 4020f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey includeVideo(result, cursor); 4030f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 4043c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey } else { 4053c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey throw new UnsupportedOperationException("Unsupported root " + rootId); 4063c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey } 4073c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey } finally { 4083c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey IoUtils.closeQuietly(cursor); 4093c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey Binder.restoreCallingIdentity(token); 4103c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey } 4113c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey return result; 4123c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey } 4133c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey 4143c22789f7fad36e3108d8597d923614c86d60064Jeff Sharkey @Override 4156e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal) 4166e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey throws FileNotFoundException { 4176e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final Ident ident = getIdentForDocId(docId); 418e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 4196e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey if (!"r".equals(mode)) { 4206e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey throw new IllegalArgumentException("Media is read-only"); 4216e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 422e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 4236e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final Uri target; 4246e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey if (TYPE_IMAGE.equals(ident.type) && ident.id != -1) { 4256e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey target = ContentUris.withAppendedId( 4266e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey Images.Media.EXTERNAL_CONTENT_URI, ident.id); 4270f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_VIDEO.equals(ident.type) && ident.id != -1) { 4280f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey target = ContentUris.withAppendedId( 4290f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey Video.Media.EXTERNAL_CONTENT_URI, ident.id); 4306e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } else if (TYPE_AUDIO.equals(ident.type) && ident.id != -1) { 4316e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey target = ContentUris.withAppendedId( 4326e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey Audio.Media.EXTERNAL_CONTENT_URI, ident.id); 4336e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } else { 4346e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey throw new UnsupportedOperationException("Unsupported document " + docId); 4356e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 436e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 4376e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey // Delegate to real provider 4386e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final long token = Binder.clearCallingIdentity(); 4396e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey try { 4406e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey return getContext().getContentResolver().openFileDescriptor(target, mode); 4416e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } finally { 4426e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey Binder.restoreCallingIdentity(token); 4436e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 444e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 445e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 4466e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey @Override 4476e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey public AssetFileDescriptor openDocumentThumbnail( 4486e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey String docId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException { 4490f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final ContentResolver resolver = getContext().getContentResolver(); 4506e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final Ident ident = getIdentForDocId(docId); 451e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 4526e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final long token = Binder.clearCallingIdentity(); 4536e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey try { 4540f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (TYPE_IMAGES_BUCKET.equals(ident.type)) { 4550f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final long id = getImageForBucketCleared(ident.id); 4560f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey return openOrCreateImageThumbnailCleared(id, signal); 4570f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_IMAGE.equals(ident.type)) { 4580f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey return openOrCreateImageThumbnailCleared(ident.id, signal); 4590f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_VIDEOS_BUCKET.equals(ident.type)) { 4600f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final long id = getVideoForBucketCleared(ident.id); 4610f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey return openOrCreateVideoThumbnailCleared(id, signal); 4620f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } else if (TYPE_VIDEO.equals(ident.type)) { 4630f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey return openOrCreateVideoThumbnailCleared(ident.id, signal); 4646e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } else { 4656e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey throw new UnsupportedOperationException("Unsupported document " + docId); 4666e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } 4676e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey } finally { 4686e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey Binder.restoreCallingIdentity(token); 469e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 470e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 471e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 4720f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private boolean isEmpty(Uri uri) { 4730f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final ContentResolver resolver = getContext().getContentResolver(); 4740f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final long token = Binder.clearCallingIdentity(); 4750f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey Cursor cursor = null; 4760f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey try { 4770f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor = resolver.query(uri, new String[] { 4780f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey BaseColumns._ID }, null, null, null); 47911ca19dc41602c091615141545a307c9d4b7f186Jeff Sharkey return (cursor == null) || (cursor.getCount() == 0); 4800f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } finally { 4810f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey IoUtils.closeQuietly(cursor); 4820f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey Binder.restoreCallingIdentity(token); 4830f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 4840f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 4850f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 4866e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey private void includeImagesRoot(MatrixCursor result) { 4870f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey int flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_RECENTS; 4880f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (isEmpty(Images.Media.EXTERNAL_CONTENT_URI)) { 4890f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey flags |= Root.FLAG_EMPTY; 490ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey sReturnedImagesEmpty = true; 4910f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 4920f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 4936e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final RowBuilder row = result.newRow(); 4940f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Root.COLUMN_ROOT_ID, TYPE_IMAGES_ROOT); 4950f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Root.COLUMN_FLAGS, flags); 49682c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Root.COLUMN_TITLE, getContext().getString(R.string.root_images)); 4970f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Root.COLUMN_DOCUMENT_ID, TYPE_IMAGES_ROOT); 49882c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Root.COLUMN_MIME_TYPES, IMAGE_MIME_TYPES); 499e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 500e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 5010f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private void includeVideosRoot(MatrixCursor result) { 5020f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey int flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_RECENTS; 5030f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (isEmpty(Video.Media.EXTERNAL_CONTENT_URI)) { 5040f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey flags |= Root.FLAG_EMPTY; 505ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey sReturnedVideosEmpty = true; 5060f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 5070f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 5080f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final RowBuilder row = result.newRow(); 5090f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Root.COLUMN_ROOT_ID, TYPE_VIDEOS_ROOT); 5100f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Root.COLUMN_FLAGS, flags); 5110f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Root.COLUMN_TITLE, getContext().getString(R.string.root_videos)); 5120f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Root.COLUMN_DOCUMENT_ID, TYPE_VIDEOS_ROOT); 5130f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Root.COLUMN_MIME_TYPES, VIDEO_MIME_TYPES); 5140f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 5150f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 5166e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey private void includeAudioRoot(MatrixCursor result) { 5170f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey int flags = Root.FLAG_LOCAL_ONLY; 5180f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (isEmpty(Audio.Media.EXTERNAL_CONTENT_URI)) { 5190f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey flags |= Root.FLAG_EMPTY; 520ca709d4f9f6ef66337b96010a150e30a5888855eJeff Sharkey sReturnedAudioEmpty = true; 5210f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 5220f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 523e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final RowBuilder row = result.newRow(); 5240f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Root.COLUMN_ROOT_ID, TYPE_AUDIO_ROOT); 5250f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Root.COLUMN_FLAGS, flags); 52682c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Root.COLUMN_TITLE, getContext().getString(R.string.root_audio)); 5270f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Root.COLUMN_DOCUMENT_ID, TYPE_AUDIO_ROOT); 52882c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Root.COLUMN_MIME_TYPES, AUDIO_MIME_TYPES); 529498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey } 530498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey 5310f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private void includeImagesRootDocument(MatrixCursor result) { 532498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey final RowBuilder row = result.newRow(); 5330f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_DOCUMENT_ID, TYPE_IMAGES_ROOT); 53482c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_DISPLAY_NAME, getContext().getString(R.string.root_images)); 53586bfd7303d107f197c6e2c86cf96efb83156043bJeff Sharkey row.add(Document.COLUMN_FLAGS, 53686bfd7303d107f197c6e2c86cf96efb83156043bJeff Sharkey Document.FLAG_DIR_PREFERS_GRID | Document.FLAG_DIR_PREFERS_LAST_MODIFIED); 53782c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); 538498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey } 539498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey 5400f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private void includeVideosRootDocument(MatrixCursor result) { 541498075b5efbc333e462104a83b95c12bd842223eJeff Sharkey final RowBuilder row = result.newRow(); 5420f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_DOCUMENT_ID, TYPE_VIDEOS_ROOT); 5430f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_DISPLAY_NAME, getContext().getString(R.string.root_videos)); 54486bfd7303d107f197c6e2c86cf96efb83156043bJeff Sharkey row.add(Document.COLUMN_FLAGS, 54586bfd7303d107f197c6e2c86cf96efb83156043bJeff Sharkey Document.FLAG_DIR_PREFERS_GRID | Document.FLAG_DIR_PREFERS_LAST_MODIFIED); 5460f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); 5470f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 5480f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 5490f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private void includeAudioRootDocument(MatrixCursor result) { 5500f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final RowBuilder row = result.newRow(); 5510f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_DOCUMENT_ID, TYPE_AUDIO_ROOT); 55282c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_DISPLAY_NAME, getContext().getString(R.string.root_audio)); 55382c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); 554e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 555e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 5560f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private interface ImagesBucketQuery { 557e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final String[] PROJECTION = new String[] { 558e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey ImageColumns.BUCKET_ID, 559e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey ImageColumns.BUCKET_DISPLAY_NAME, 560e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey ImageColumns.DATE_MODIFIED }; 5614c9dda96c93853561519de9934167ff337e3b281Jeff Sharkey final String SORT_ORDER = ImageColumns.BUCKET_ID + ", " + ImageColumns.DATE_MODIFIED 5624c9dda96c93853561519de9934167ff337e3b281Jeff Sharkey + " DESC"; 563e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 564e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int BUCKET_ID = 0; 565e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int BUCKET_DISPLAY_NAME = 1; 566e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int DATE_MODIFIED = 2; 567e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 568e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 5690f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private void includeImagesBucket(MatrixCursor result, Cursor cursor) { 5700f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final long id = cursor.getLong(ImagesBucketQuery.BUCKET_ID); 5710f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final String docId = getDocIdForIdent(TYPE_IMAGES_BUCKET, id); 572e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 573e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final RowBuilder row = result.newRow(); 57482c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_DOCUMENT_ID, docId); 5750f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_DISPLAY_NAME, 5760f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor.getString(ImagesBucketQuery.BUCKET_DISPLAY_NAME)); 57782c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); 57882c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_LAST_MODIFIED, 5790f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor.getLong(ImagesBucketQuery.DATE_MODIFIED) * DateUtils.SECOND_IN_MILLIS); 58086bfd7303d107f197c6e2c86cf96efb83156043bJeff Sharkey row.add(Document.COLUMN_FLAGS, Document.FLAG_DIR_PREFERS_GRID 58186bfd7303d107f197c6e2c86cf96efb83156043bJeff Sharkey | Document.FLAG_SUPPORTS_THUMBNAIL | Document.FLAG_DIR_PREFERS_LAST_MODIFIED 58286bfd7303d107f197c6e2c86cf96efb83156043bJeff Sharkey | Document.FLAG_DIR_HIDE_GRID_TITLES); 583e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 584e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 585e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey private interface ImageQuery { 586e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final String[] PROJECTION = new String[] { 587e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey ImageColumns._ID, 588e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey ImageColumns.DISPLAY_NAME, 589e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey ImageColumns.MIME_TYPE, 590e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey ImageColumns.SIZE, 591e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey ImageColumns.DATE_MODIFIED }; 592e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 593e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int _ID = 0; 594e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int DISPLAY_NAME = 1; 595e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int MIME_TYPE = 2; 596e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int SIZE = 3; 597e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int DATE_MODIFIED = 4; 598e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 599e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 600e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey private void includeImage(MatrixCursor result, Cursor cursor) { 601e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final long id = cursor.getLong(ImageQuery._ID); 6026e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final String docId = getDocIdForIdent(TYPE_IMAGE, id); 603e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 604e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final RowBuilder row = result.newRow(); 60582c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_DOCUMENT_ID, docId); 60682c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_DISPLAY_NAME, cursor.getString(ImageQuery.DISPLAY_NAME)); 60782c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_SIZE, cursor.getLong(ImageQuery.SIZE)); 60882c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_MIME_TYPE, cursor.getString(ImageQuery.MIME_TYPE)); 60982c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_LAST_MODIFIED, 610e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey cursor.getLong(ImageQuery.DATE_MODIFIED) * DateUtils.SECOND_IN_MILLIS); 61182c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_THUMBNAIL); 612e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 613e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 6140f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private interface VideosBucketQuery { 6150f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final String[] PROJECTION = new String[] { 6160f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoColumns.BUCKET_ID, 6170f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoColumns.BUCKET_DISPLAY_NAME, 6180f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoColumns.DATE_MODIFIED }; 6194c9dda96c93853561519de9934167ff337e3b281Jeff Sharkey final String SORT_ORDER = VideoColumns.BUCKET_ID + ", " + VideoColumns.DATE_MODIFIED 6204c9dda96c93853561519de9934167ff337e3b281Jeff Sharkey + " DESC"; 6210f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 6220f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final int BUCKET_ID = 0; 6230f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final int BUCKET_DISPLAY_NAME = 1; 6240f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final int DATE_MODIFIED = 2; 6250f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 6260f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 6270f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private void includeVideosBucket(MatrixCursor result, Cursor cursor) { 6280f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final long id = cursor.getLong(VideosBucketQuery.BUCKET_ID); 6290f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final String docId = getDocIdForIdent(TYPE_VIDEOS_BUCKET, id); 6300f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 6310f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final RowBuilder row = result.newRow(); 6320f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_DOCUMENT_ID, docId); 6330f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_DISPLAY_NAME, 6340f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor.getString(VideosBucketQuery.BUCKET_DISPLAY_NAME)); 6350f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); 6360f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_LAST_MODIFIED, 6370f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor.getLong(VideosBucketQuery.DATE_MODIFIED) * DateUtils.SECOND_IN_MILLIS); 63886bfd7303d107f197c6e2c86cf96efb83156043bJeff Sharkey row.add(Document.COLUMN_FLAGS, Document.FLAG_DIR_PREFERS_GRID 63986bfd7303d107f197c6e2c86cf96efb83156043bJeff Sharkey | Document.FLAG_SUPPORTS_THUMBNAIL | Document.FLAG_DIR_PREFERS_LAST_MODIFIED 64086bfd7303d107f197c6e2c86cf96efb83156043bJeff Sharkey | Document.FLAG_DIR_HIDE_GRID_TITLES); 6410f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 6420f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 6430f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private interface VideoQuery { 6440f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final String[] PROJECTION = new String[] { 6450f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoColumns._ID, 6460f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoColumns.DISPLAY_NAME, 6470f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoColumns.MIME_TYPE, 6480f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoColumns.SIZE, 6490f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoColumns.DATE_MODIFIED }; 6500f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 6510f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final int _ID = 0; 6520f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final int DISPLAY_NAME = 1; 6530f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final int MIME_TYPE = 2; 6540f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final int SIZE = 3; 6550f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final int DATE_MODIFIED = 4; 6560f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 6570f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 6580f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private void includeVideo(MatrixCursor result, Cursor cursor) { 6590f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final long id = cursor.getLong(VideoQuery._ID); 6600f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final String docId = getDocIdForIdent(TYPE_VIDEO, id); 6610f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 6620f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final RowBuilder row = result.newRow(); 6630f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_DOCUMENT_ID, docId); 6640f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_DISPLAY_NAME, cursor.getString(VideoQuery.DISPLAY_NAME)); 6650f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_SIZE, cursor.getLong(VideoQuery.SIZE)); 6660f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_MIME_TYPE, cursor.getString(VideoQuery.MIME_TYPE)); 6670f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_LAST_MODIFIED, 6680f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor.getLong(VideoQuery.DATE_MODIFIED) * DateUtils.SECOND_IN_MILLIS); 6690f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_THUMBNAIL); 6700f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 6710f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 672e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey private interface ArtistQuery { 673e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final String[] PROJECTION = new String[] { 674e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey BaseColumns._ID, 675e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey ArtistColumns.ARTIST }; 676e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 677e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int _ID = 0; 678e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int ARTIST = 1; 679e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 680e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 681e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey private void includeArtist(MatrixCursor result, Cursor cursor) { 682e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final long id = cursor.getLong(ArtistQuery._ID); 6836e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final String docId = getDocIdForIdent(TYPE_ARTIST, id); 684e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 685e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final RowBuilder row = result.newRow(); 68682c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_DOCUMENT_ID, docId); 68782c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_DISPLAY_NAME, cursor.getString(ArtistQuery.ARTIST)); 68882c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); 689e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 690e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 691e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey private interface AlbumQuery { 692e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final String[] PROJECTION = new String[] { 693e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey BaseColumns._ID, 694e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey AlbumColumns.ALBUM }; 695e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 696e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int _ID = 0; 697e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int ALBUM = 1; 698e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 699e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 700e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey private void includeAlbum(MatrixCursor result, Cursor cursor) { 701e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final long id = cursor.getLong(AlbumQuery._ID); 7026e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final String docId = getDocIdForIdent(TYPE_ALBUM, id); 703e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 704e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final RowBuilder row = result.newRow(); 70582c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_DOCUMENT_ID, docId); 70682c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_DISPLAY_NAME, cursor.getString(AlbumQuery.ALBUM)); 70782c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); 708e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 709e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 710e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey private interface SongQuery { 711e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final String[] PROJECTION = new String[] { 712e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey AudioColumns._ID, 713e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey AudioColumns.TITLE, 714e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey AudioColumns.MIME_TYPE, 715e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey AudioColumns.SIZE, 716e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey AudioColumns.DATE_MODIFIED }; 717e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 718e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int _ID = 0; 719e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int TITLE = 1; 720e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int MIME_TYPE = 2; 721e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int SIZE = 3; 722e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final int DATE_MODIFIED = 4; 723e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 724e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 7256e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey private void includeAudio(MatrixCursor result, Cursor cursor) { 726e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final long id = cursor.getLong(SongQuery._ID); 7276e21463c8302c6bae572f07b3e0ea832d8ae9f6aJeff Sharkey final String docId = getDocIdForIdent(TYPE_AUDIO, id); 728e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 729e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey final RowBuilder row = result.newRow(); 73082c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_DOCUMENT_ID, docId); 73182c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_DISPLAY_NAME, cursor.getString(SongQuery.TITLE)); 73282c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_SIZE, cursor.getLong(SongQuery.SIZE)); 73382c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_MIME_TYPE, cursor.getString(SongQuery.MIME_TYPE)); 73482c4ab2390570a461e297a4e319b5358d55f757bJeff Sharkey row.add(Document.COLUMN_LAST_MODIFIED, 735e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey cursor.getLong(SongQuery.DATE_MODIFIED) * DateUtils.SECOND_IN_MILLIS); 736e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey } 737e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey 7380f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private interface ImagesBucketThumbnailQuery { 739240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey final String[] PROJECTION = new String[] { 740240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey ImageColumns._ID, 741240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey ImageColumns.BUCKET_ID, 742240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey ImageColumns.DATE_MODIFIED }; 743240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey 744240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey final int _ID = 0; 745240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey final int BUCKET_ID = 1; 746240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey final int DATE_MODIFIED = 2; 747240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey } 748240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey 7490f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private long getImageForBucketCleared(long bucketId) throws FileNotFoundException { 750240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey final ContentResolver resolver = getContext().getContentResolver(); 751240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey Cursor cursor = null; 752240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey try { 753240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey cursor = resolver.query(Images.Media.EXTERNAL_CONTENT_URI, 7540f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey ImagesBucketThumbnailQuery.PROJECTION, ImageColumns.BUCKET_ID + "=" + bucketId, 7550f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey null, ImageColumns.DATE_MODIFIED + " DESC"); 7560f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (cursor.moveToFirst()) { 7570f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey return cursor.getLong(ImagesBucketThumbnailQuery._ID); 7580f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 7590f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } finally { 7600f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey IoUtils.closeQuietly(cursor); 7610f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 7620f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey throw new FileNotFoundException("No video found for bucket"); 7630f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 7640f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 7650f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private interface ImageThumbnailQuery { 7660f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final String[] PROJECTION = new String[] { 7670f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey Images.Thumbnails.DATA }; 7680f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 7690f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final int _DATA = 0; 7700f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 7710f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 7725082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey private ParcelFileDescriptor openImageThumbnailCleared(long id, CancellationSignal signal) 7730f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey throws FileNotFoundException { 7740f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final ContentResolver resolver = getContext().getContentResolver(); 7755082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey 7760f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey Cursor cursor = null; 7770f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey try { 7780f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor = resolver.query(Images.Thumbnails.EXTERNAL_CONTENT_URI, 7790f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey ImageThumbnailQuery.PROJECTION, Images.Thumbnails.IMAGE_ID + "=" + id, null, 7800f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey null, signal); 7810f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (cursor.moveToFirst()) { 7820f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final String data = cursor.getString(ImageThumbnailQuery._DATA); 7835082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey return ParcelFileDescriptor.open( 7845082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey new File(data), ParcelFileDescriptor.MODE_READ_ONLY); 7850f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 7860f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } finally { 7870f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey IoUtils.closeQuietly(cursor); 7880f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 7890f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey return null; 7900f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 7910f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 7920f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private AssetFileDescriptor openOrCreateImageThumbnailCleared( 7930f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey long id, CancellationSignal signal) throws FileNotFoundException { 7940f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final ContentResolver resolver = getContext().getContentResolver(); 7950f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 7965082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey ParcelFileDescriptor pfd = openImageThumbnailCleared(id, signal); 7975082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey if (pfd == null) { 7980f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey // No thumbnail yet, so generate. This is messy, since we drop the 7990f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey // Bitmap on the floor, but its the least-complicated way. 8000f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final BitmapFactory.Options opts = new BitmapFactory.Options(); 8010f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey opts.inJustDecodeBounds = true; 8020f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey Images.Thumbnails.getThumbnail(resolver, id, Images.Thumbnails.MINI_KIND, opts); 8030f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 8045082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey pfd = openImageThumbnailCleared(id, signal); 8050f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 8060f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 8075082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey if (pfd == null) { 8080f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey // Phoey, fallback to full image 8090f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final Uri fullUri = ContentUris.withAppendedId(Images.Media.EXTERNAL_CONTENT_URI, id); 8105082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey pfd = resolver.openFileDescriptor(fullUri, "r", signal); 8110f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 8120f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 8135082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey final int orientation = queryOrientationForImage(id, signal); 8145082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey final Bundle extras; 8155082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey if (orientation != 0) { 8165082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey extras = new Bundle(1); 8175082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey extras.putInt(DocumentsContract.EXTRA_ORIENTATION, orientation); 8185082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey } else { 8195082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey extras = null; 8205082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey } 8215082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey 8225082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH, extras); 8230f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 8240f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 8250f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private interface VideosBucketThumbnailQuery { 8260f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final String[] PROJECTION = new String[] { 8270f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoColumns._ID, 8280f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoColumns.BUCKET_ID, 8290f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoColumns.DATE_MODIFIED }; 8300f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 8310f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final int _ID = 0; 8320f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final int BUCKET_ID = 1; 8330f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final int DATE_MODIFIED = 2; 8340f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 8350f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 8360f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private long getVideoForBucketCleared(long bucketId) 8370f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey throws FileNotFoundException { 8380f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final ContentResolver resolver = getContext().getContentResolver(); 8390f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey Cursor cursor = null; 8400f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey try { 8410f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor = resolver.query(Video.Media.EXTERNAL_CONTENT_URI, 8420f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideosBucketThumbnailQuery.PROJECTION, VideoColumns.BUCKET_ID + "=" + bucketId, 8430f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey null, VideoColumns.DATE_MODIFIED + " DESC"); 8440f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (cursor.moveToFirst()) { 8450f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey return cursor.getLong(VideosBucketThumbnailQuery._ID); 8460f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 8470f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } finally { 8480f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey IoUtils.closeQuietly(cursor); 8490f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 8500f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey throw new FileNotFoundException("No video found for bucket"); 8510f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 8520f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 8530f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private interface VideoThumbnailQuery { 8540f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final String[] PROJECTION = new String[] { 8550f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey Video.Thumbnails.DATA }; 8560f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 8570f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final int _DATA = 0; 8580f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 8590f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 8600f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private AssetFileDescriptor openVideoThumbnailCleared(long id, CancellationSignal signal) 8610f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey throws FileNotFoundException { 8620f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final ContentResolver resolver = getContext().getContentResolver(); 8630f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey Cursor cursor = null; 8640f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey try { 8650f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey cursor = resolver.query(Video.Thumbnails.EXTERNAL_CONTENT_URI, 8660f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey VideoThumbnailQuery.PROJECTION, Video.Thumbnails.VIDEO_ID + "=" + id, null, 8670f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey null, signal); 868240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey if (cursor.moveToFirst()) { 8690f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final String data = cursor.getString(VideoThumbnailQuery._DATA); 8700f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey return new AssetFileDescriptor(ParcelFileDescriptor.open( 8710f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey new File(data), ParcelFileDescriptor.MODE_READ_ONLY), 0, 8720f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey AssetFileDescriptor.UNKNOWN_LENGTH); 873240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey } 874240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey } finally { 875240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey IoUtils.closeQuietly(cursor); 876240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey } 877240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey return null; 878240f6b3ea7c4daed5a8690ae27a703e62da96744Jeff Sharkey } 8790f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 8800f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey private AssetFileDescriptor openOrCreateVideoThumbnailCleared( 8810f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey long id, CancellationSignal signal) throws FileNotFoundException { 8820f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final ContentResolver resolver = getContext().getContentResolver(); 8830f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 8840f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey AssetFileDescriptor afd = openVideoThumbnailCleared(id, signal); 8850f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey if (afd == null) { 8860f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey // No thumbnail yet, so generate. This is messy, since we drop the 8870f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey // Bitmap on the floor, but its the least-complicated way. 8880f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey final BitmapFactory.Options opts = new BitmapFactory.Options(); 8890f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey opts.inJustDecodeBounds = true; 8900f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey Video.Thumbnails.getThumbnail(resolver, id, Video.Thumbnails.MINI_KIND, opts); 8910f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 8920f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey afd = openVideoThumbnailCleared(id, signal); 8930f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 8940f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey 8950f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey return afd; 8960f90e312f1eeb52b3c9cd668f5593fd72217f9dbJeff Sharkey } 8975082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey 8985082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey private interface ImageOrientationQuery { 8995082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey final String[] PROJECTION = new String[] { 9005082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey ImageColumns.ORIENTATION }; 9015082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey 9025082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey final int ORIENTATION = 0; 9035082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey } 9045082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey 9055082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey private int queryOrientationForImage(long id, CancellationSignal signal) { 9065082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey final ContentResolver resolver = getContext().getContentResolver(); 9075082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey 9085082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey Cursor cursor = null; 9095082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey try { 9105082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey cursor = resolver.query(Images.Media.EXTERNAL_CONTENT_URI, 9115082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey ImageOrientationQuery.PROJECTION, ImageColumns._ID + "=" + id, null, null, 9125082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey signal); 9135082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey if (cursor.moveToFirst()) { 9145082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey return cursor.getInt(ImageOrientationQuery.ORIENTATION); 9155082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey } else { 9165082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey Log.w(TAG, "Missing orientation data for " + id); 9175082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey return 0; 9185082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey } 9195082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey } finally { 9205082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey IoUtils.closeQuietly(cursor); 9215082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey } 9225082b808a9821a43c37b58aaf9f98b8daa415fefJeff Sharkey } 923e215ab5b4f1eeeafc75f5f17c92dd21e8d2161ebJeff Sharkey} 924