MediaProvider.java revision fb598dd5ac235f6282aac23b7b9c214f2fd62a7a
1702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project/* 2702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 3702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * you may not use this file except in compliance with the License. 6702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * You may obtain a copy of the License at 7702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 8702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 10702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * See the License for the specific language governing permissions and 14702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * limitations under the License. 15702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 16702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 17702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectpackage com.android.providers.media; 18702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 19702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.app.SearchManager; 20bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.BroadcastReceiver; 21bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ComponentName; 22bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ContentProvider; 23bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ContentProviderOperation; 24bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ContentProviderResult; 25bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ContentResolver; 26bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ContentUris; 27bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ContentValues; 28bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.Context; 29bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.Intent; 30bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.IntentFilter; 31bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.OperationApplicationException; 32bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ServiceConnection; 33bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.UriMatcher; 34702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.Cursor; 35ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissenimport android.database.DatabaseUtils; 360027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissenimport android.database.MatrixCursor; 37702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.SQLException; 38702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteDatabase; 39702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper; 40702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteQueryBuilder; 41702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.graphics.Bitmap; 42702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.graphics.BitmapFactory; 43b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwoodimport android.media.MediaFile; 44702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.media.MediaScanner; 45b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport android.media.MiniThumbFile; 469114b186ffb26cf0ec6af6eb01ccdf47228a355fMike Lockwoodimport android.media.MtpConstants; 47702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.net.Uri; 48702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Binder; 49702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Environment; 50702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.FileUtils; 51702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Handler; 52ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Changimport android.os.HandlerThread; 53702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Message; 54702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.ParcelFileDescriptor; 55702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Process; 56d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwoodimport android.os.RemoteException; 574f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwoodimport android.os.SystemProperties; 58702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.BaseColumns; 59702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore; 60702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Audio; 615bf5c26a3499d584332074baab97392696ed9614Ray Chenimport android.provider.MediaStore.Files; 62702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Images; 63702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.MediaColumns; 64702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Video; 6516dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwoodimport android.provider.MediaStore.Files.FileColumns; 665bf5c26a3499d584332074baab97392696ed9614Ray Chenimport android.provider.MediaStore.Images.ImageColumns; 67702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.text.TextUtils; 68702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.util.Log; 69702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 70702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.File; 71702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileInputStream; 72702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileNotFoundException; 73702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.IOException; 74702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.OutputStream; 75702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.text.Collator; 76cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissenimport java.util.ArrayList; 77702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashMap; 78702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashSet; 79702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.Iterator; 80f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissenimport java.util.List; 81b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport java.util.PriorityQueue; 828a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huberimport java.util.Stack; 83702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 84702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project/** 85702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Media content provider. See {@link android.provider.MediaStore} for details. 86702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Separate databases are kept for each external storage card we see (using the 87702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * card's ID as an index). The content visible at content://media/external/... 88702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * changes with the card. 89702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 90702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectpublic class MediaProvider extends ContentProvider { 91702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri MEDIA_URI = Uri.parse("content://media"); 92702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri ALBUMART_URI = Uri.parse("content://media/external/audio/albumart"); 93b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int ALBUM_THUMB = 1; 94b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int IMAGE_THUMB = 2; 95702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 96702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final HashMap<String, String> sArtistAlbumsMap = new HashMap<String, String>(); 97d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen private static final HashMap<String, String> sFolderArtMap = new HashMap<String, String>(); 98702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A HashSet of paths that are pending creation of album art thumbnails. 1008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private HashSet mPendingThumbs = new HashSet(); 1018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 1028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A Stack of outstanding thumbnail requests. 1038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private Stack mThumbRequestStack = new Stack(); 1048a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 10520434e032e498b716f87cce2f23dd646819218bfRay Chen // The lock of mMediaThumbQueue protects both mMediaThumbQueue and mCurrentThumbRequest. 10620434e032e498b716f87cce2f23dd646819218bfRay Chen private MediaThumbRequest mCurrentThumbRequest = null; 107b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private PriorityQueue<MediaThumbRequest> mMediaThumbQueue = 108b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen new PriorityQueue<MediaThumbRequest>(MediaThumbRequest.PRIORITY_NORMAL, 109b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaThumbRequest.getComparator()); 110b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 111a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // For compatibility with the approximately 0 apps that used mediaprovider search in 112a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // releases 1.0, 1.1 or 1.5 113a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsLegacy = new String[] { 114a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 115a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 116a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 117a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 118a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 119a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 120a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "0 AS " + SearchManager.SUGGEST_COLUMN_ICON_2, 121a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 122a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 123a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data1 ELSE artist END AS data1", 124a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data2 ELSE " + 125a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE WHEN grouporder=2 THEN NULL ELSE album END END AS data2", 126a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "match as ar", 127a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA, 128a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "grouporder", 129ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen "NULL AS itemorder" // We should be sorting by the artist/album/title keys, but that 130ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen // column is not available here, and the list is already sorted. 131a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 132a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsFancy = new String[] { 133a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 134a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 135a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Artists.ARTIST, 136a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Albums.ALBUM, 137a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.TITLE, 138a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data1", 139a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data2", 140a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 14163f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // If this array gets changed, please update the constant below to point to the correct item. 142a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsBasic = new String[] { 143a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 144a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 145a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 146a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 147a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 148a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 149a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 150a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 15163f748ff8b258d9110038778a006b3000164fbeeSatish Sampath "(CASE WHEN grouporder=1 THEN '%1'" + // %1 gets replaced with localized string. 15263f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE CASE WHEN grouporder=3 THEN artist || ' - ' || album" + 153e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen " ELSE CASE WHEN text2!='" + MediaStore.UNKNOWN_STRING + "' THEN text2" + 15463f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE NULL END END END) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2, 155a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA 156a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 15763f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // Position of the TEXT_2 item in the above array. 15863f748ff8b258d9110038778a006b3000164fbeeSatish Sampath private final int SEARCH_COLUMN_BASIC_TEXT2 = 5; 159a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 1601717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood private static final String[] mMediaTableColumns = new String[] { 16116dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood FileColumns._ID, 162afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood FileColumns.MEDIA_TYPE, 1631717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood }; 1641717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 165a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen private Uri mAlbumArtBaseUri = Uri.parse("content://media/external/audio/albumart"); 166a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen 167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private BroadcastReceiver mUnmountReceiver = new BroadcastReceiver() { 168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 169702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onReceive(Context context, Intent intent) { 170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (intent.getAction().equals(Intent.ACTION_MEDIA_EJECT)) { 171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Remove the external volume and then notify all cursors backed by 172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // data on that volume 173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project detachVolume(Uri.parse("content://media/external")); 174d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen sFolderArtMap.clear(); 175b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MiniThumbFile.reset(); 176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 179702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 180d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // set to disable sending events when the operation originates from MTP 181d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private boolean mDisableMtpObjectCallbacks; 182d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 183d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private final SQLiteDatabase.CustomFunction mObjectRemovedCallback = 184d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood new SQLiteDatabase.CustomFunction() { 185d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void callback(String[] args) { 186d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // do nothing if the operation originated from MTP 187d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mDisableMtpObjectCallbacks) return; 188d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 189d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.d(TAG, "object removed " + args[0]); 190d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood IMtpService mtpService = mMtpService; 191d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mtpService != null) { 192d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood try { 193d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood sendObjectRemoved(Integer.parseInt(args[0])); 194d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } catch (NumberFormatException e) { 195d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.e(TAG, "NumberFormatException in mObjectRemovedCallback", e); 196d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 197d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 198d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 199d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood }; 200d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 2014f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood // path to external storage, or media directory in internal storage 2029541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood private static String mMediaStoragePath; 2039541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood // legacy path, which needs to get remapped to mMediaStoragePath 2044f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood private static String mExternalStoragePath; 2054f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood 206d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood /* package */ static String externalToMediaPath(String path) { 2079541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood // convert external storage path to media path 2089541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood if (path != null && mMediaStoragePath != null 2099541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood && mExternalStoragePath != null 2109541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood && path.startsWith(mExternalStoragePath)) { 2119541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood path = mMediaStoragePath + path.substring(mExternalStoragePath.length()); 2124f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood } 2134f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood return path; 2144f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood } 2154f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood 2169541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood private static String mediaToExternalPath(String path) { 2179541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood // convert external storage path to media path 2189541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood if (path != null && mMediaStoragePath != null 2199541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood && mExternalStoragePath != null 2209541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood && path.startsWith(mMediaStoragePath)) { 2219541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood path = mExternalStoragePath + path.substring(mMediaStoragePath.length()); 2229541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood } 2239541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood return path; 2249541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood } 2259541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood 226d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood private static ContentValues mediaToExternalPath(ContentValues values) { 227795fcfcfea623b2bd27d291eae575dfa20350e34Mike Lockwood String path = values.getAsString(MediaStore.MediaColumns.DATA); 228795fcfcfea623b2bd27d291eae575dfa20350e34Mike Lockwood if (path != null) { 229d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood String fixedPath = mediaToExternalPath(path); 230795fcfcfea623b2bd27d291eae575dfa20350e34Mike Lockwood if (!path.equals(fixedPath)) { 231795fcfcfea623b2bd27d291eae575dfa20350e34Mike Lockwood values = new ContentValues(values); 232795fcfcfea623b2bd27d291eae575dfa20350e34Mike Lockwood values.put(MediaStore.MediaColumns.DATA, fixedPath); 233795fcfcfea623b2bd27d291eae575dfa20350e34Mike Lockwood } 234795fcfcfea623b2bd27d291eae575dfa20350e34Mike Lockwood } 235795fcfcfea623b2bd27d291eae575dfa20350e34Mike Lockwood return values; 236795fcfcfea623b2bd27d291eae575dfa20350e34Mike Lockwood } 237795fcfcfea623b2bd27d291eae575dfa20350e34Mike Lockwood 238702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Wrapper class for a specific database (associated with one particular 240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * external card, or with internal storage). Can open the actual database 241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * on demand, create and upgrade the schema, etc. 242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 243d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private final class DatabaseHelper extends SQLiteOpenHelper { 244702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final Context mContext; 2455524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood final String mName; 246702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final boolean mInternal; // True if this is the internal database 2475524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood boolean mUpgradeAttempted; // Used for upgrade error handling 248702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 249702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // In memory caches of artist and album data. 250702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mArtistCache = new HashMap<String, Long>(); 251702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mAlbumCache = new HashMap<String, Long>(); 252702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 253702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public DatabaseHelper(Context context, String name, boolean internal) { 254702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project super(context, name, null, DATABASE_VERSION); 255702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext = context; 2565524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mName = name; 257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mInternal = internal; 258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Creates database the first time we try to open it. 262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 263702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onCreate(final SQLiteDatabase db) { 265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDatabase(db, mInternal, 0, DATABASE_VERSION); 266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 267702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Updates the database format when a new content provider is used 270702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * with an older database format. 271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onUpgrade(final SQLiteDatabase db, final int oldV, final int newV) { 2745524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mUpgradeAttempted = true; 275702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDatabase(db, mInternal, oldV, newV); 276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 277702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2785524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood public synchronized SQLiteDatabase getWritableDatabase() { 2795524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood SQLiteDatabase result = null; 2805524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mUpgradeAttempted = false; 2815524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood try { 2825524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood result = super.getWritableDatabase(); 2835524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } catch (Exception e) { 2845524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood if (!mUpgradeAttempted) { 2855524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood Log.e(TAG, "failed to open database " + mName, e); 2865524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood return null; 2875524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 2885524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 2895524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood 2905524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood // If we failed to open the database during an upgrade, delete the file and try again. 2915524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood // This will result in the creation of a fresh database, which will be repopulated 2925524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood // when the media scanner runs. 2935524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood if (result == null && mUpgradeAttempted) { 2945524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mContext.getDatabasePath(mName).delete(); 2955524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood result = super.getWritableDatabase(); 2965524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 2975524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood return result; 2985524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 2995524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood 300702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Touch this particular database and garbage collect old databases. 302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * An LRU cache system is used to clean up databases for old external 303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * storage volumes. 304702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 305702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onOpen(SQLiteDatabase db) { 30736d7136bebac6ea5738fb653a74dcd6c71e4cd58Dmitry Dolinsky 30836d7136bebac6ea5738fb653a74dcd6c71e4cd58Dmitry Dolinsky // Turn off WAL optimization as it appears to cause difficult to repoduce 30936d7136bebac6ea5738fb653a74dcd6c71e4cd58Dmitry Dolinsky // disk i/o errors. 31036d7136bebac6ea5738fb653a74dcd6c71e4cd58Dmitry Dolinsky db.disableWriteAheadLogging(); 31136d7136bebac6ea5738fb653a74dcd6c71e4cd58Dmitry Dolinsky 312702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mInternal) return; // The internal database is kept separately. 313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 314d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood db.addCustomFunction("_OBJECT_REMOVED", 1, mObjectRemovedCallback); 315d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 316702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 317702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(db.getPath()); 318702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long now = System.currentTimeMillis(); 319702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(now); 320702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 321702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases if we are over the limit 322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] databases = mContext.databaseList(); 323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count = databases.length; 324702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int limit = MAX_EXTERNAL_DATABASES; 325702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 326702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete external databases that have not been used in the past two months 327702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long twoMonthsAgo = now - OBSOLETE_DATABASE_DB; 328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File other = mContext.getDatabasePath(databases[i]); 330702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_DATABASE_NAME.equals(databases[i]) || file.equals(other)) { 331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 332702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 333702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.equals(other)) { 334702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // reduce limit to account for the existence of the database we 335702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // are about to open, which we removed from the list. 336702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project limit--; 337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = other.lastModified(); 340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (time < twoMonthsAgo) { 341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[i]); 342702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[i]); 343702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 344702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases until 350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we are no longer over the limit 351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (count > limit) { 352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lruIndex = -1; 353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long lruTime = 0; 354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (databases[i] != null) { 357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = mContext.getDatabasePath(databases[i]).lastModified(); 358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruTime == 0 || time < lruTime) { 359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruIndex = i; 360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruTime = time; 361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used database 366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruIndex != -1) { 367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[lruIndex]); 368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[lruIndex]); 369702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[lruIndex] = null; 370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 376d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private IMtpService mMtpService; 377d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 378d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private final ServiceConnection mMtpServiceConnection = new ServiceConnection() { 379d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void onServiceConnected(ComponentName className, android.os.IBinder service) { 380d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.d(TAG, "mMtpService connected"); 381d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mMtpService = IMtpService.Stub.asInterface(service); 382d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 383d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 384d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void onServiceDisconnected(ComponentName className) { 385d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.d(TAG, "mMtpService disconnected"); 386d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mMtpService = null; 387d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 388d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood }; 389d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public boolean onCreate() { 392d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood final Context context = getContext(); 393d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 394acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums._ID, "audio.album_id AS " + 395acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums._ID); 396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM, "album"); 397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_KEY, "album_key"); 398acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.FIRST_YEAR, "MIN(year) AS " + 399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.FIRST_YEAR); 400acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.LAST_YEAR, "MAX(year) AS " + 401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.LAST_YEAR); 402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST, "artist"); 403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_ID, "artist"); 404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_KEY, "artist_key"); 405acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS, "count(*) AS " + 406acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.NUMBER_OF_SONGS); 407acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_ART, "album_art._data AS " + 408acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.ALBUM_ART); 409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 41063f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2] = 41163f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2].replaceAll( 412d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "%1", context.getString(R.string.artist_label)); 413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases = new HashMap<String, DatabaseHelper>(); 414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(INTERNAL_VOLUME); 415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project IntentFilter iFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT); 417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project iFilter.addDataScheme("file"); 418d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood context.registerReceiver(mUnmountReceiver, iFilter); 419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4204f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood // figure out correct path to use for external storage 4219541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood mMediaStoragePath = SystemProperties.get("ro.media.storage"); 4229541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood if (mMediaStoragePath == null || mMediaStoragePath.length() == 0) { 4239541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood mMediaStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath(); 4244f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood } else { 4254f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood // apps may use the legacy /mnt/sdcard path instead. 4269541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood // if so, we need to transform the paths to use the mMediaStoragePath prefix 4279541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath(); 4289541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood if (mMediaStoragePath.equals(mExternalStoragePath)) { 4294f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood // paths are equal - no remapping necessary 4309541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood mExternalStoragePath = null; 4314f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood } 4324f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood } 4334f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood 434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // open external database if external storage is mounted 435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String state = Environment.getExternalStorageState(); 436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Environment.MEDIA_MOUNTED.equals(state) || 437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(EXTERNAL_VOLUME); 439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 441ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang HandlerThread ht = new HandlerThread("thumbs thread", Process.THREAD_PRIORITY_BACKGROUND); 442ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang ht.start(); 443ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang mThumbHandler = new Handler(ht.getLooper()) { 444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void handleMessage(Message msg) { 446b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (msg.what == IMAGE_THUMB) { 447b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 44820434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest = mMediaThumbQueue.poll(); 449b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 45020434e032e498b716f87cce2f23dd646819218bfRay Chen if (mCurrentThumbRequest == null) { 451b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Log.w(TAG, "Have message but no request?"); 452b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else { 453b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen try { 45420434e032e498b716f87cce2f23dd646819218bfRay Chen File origFile = new File(mCurrentThumbRequest.mPath); 4554d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen if (origFile.exists() && origFile.length() > 0) { 45620434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.execute(); 4574d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } else { 4584d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen // original file hasn't been stored yet 4594d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen synchronized (mMediaThumbQueue) { 46020434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original file hasn't been stored yet: " + mCurrentThumbRequest.mPath); 4614d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 4624d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 463b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } catch (IOException ex) { 4641d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 4651d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen } catch (UnsupportedOperationException ex) { 4661d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // This could happen if we unplug the sd card during insert/update/delete 4671d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // See getDatabaseForUri. 4681d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 46922c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren } catch (OutOfMemoryError err) { 47022c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren /* 47122c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * Note: Catching Errors is in most cases considered 47222c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * bad practice. However, in this case it is 47322c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * motivated by the fact that corrupt or very large 47422c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * images may cause a huge allocation to be 47522c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * requested and denied. The bitmap handling API in 47622c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * Android offers no other way to guard against 47722c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * these problems than by catching OutOfMemoryError. 47822c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren */ 47922c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren Log.w(TAG, err); 480b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } finally { 48120434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 48220434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.DONE; 48320434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 484b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 485b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 486b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 487b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else if (msg.what == ALBUM_THUMB) { 488b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ThumbData d; 489b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mThumbRequestStack) { 490b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen d = (ThumbData)mThumbRequestStack.pop(); 491b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 4928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 493b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen makeThumbInternal(d); 494b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mPendingThumbs) { 495b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen mPendingThumbs.remove(d.path); 496b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 4978a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 501d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood context.bindService(new Intent(context, MtpService.class), 502d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mMtpServiceConnection, Context.BIND_AUTO_CREATE); 503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 506afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood private static final String IMAGE_COLUMNS = 507afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data,_size,_display_name,mime_type,title,date_added," + 508afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_modified,description,picasa_id,isprivate,latitude,longitude," + 509afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "datetaken,orientation,mini_thumb_magic,bucket_id,bucket_display_name"; 510afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 511805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen private static final String AUDIO_COLUMNSv99 = 512afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data,_display_name,_size,mime_type,date_added," + 513afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_modified,title,title_key,duration,artist_id,composer,album_id," + 514afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "track,year,is_ringtone,is_music,is_alarm,is_notification,is_podcast," + 515afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bookmark"; 516afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 517805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen private static final String AUDIO_COLUMNSv100 = 518805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "_data,_display_name,_size,mime_type,date_added," + 519805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "date_modified,title,title_key,duration,artist_id,composer,album_id," + 520805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "track,year,is_ringtone,is_music,is_alarm,is_notification,is_podcast," + 521805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "bookmark,album_artist"; 522805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen 523afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood private static final String VIDEO_COLUMNS = 524afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data,_display_name,_size,mime_type,date_added,date_modified," + 525afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "title,duration,artist,album,resolution,description,isprivate,tags," + 526afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "category,language,mini_thumb_data,latitude,longitude,datetaken," + 527afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mini_thumb_magic,bucket_id,bucket_display_name, bookmark"; 528afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 529afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood private static final String PLAYLIST_COLUMNS = "_data,name,date_added,date_modified"; 530afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method takes care of updating all the tables in the database to the 533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * current version, creating them if necessary. 534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method can only update databases at schema 63 or higher, which was 535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * created August 1, 2008. Older database will be cleared and recreated. 536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db Database 537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param internal True if this is the internal media database 538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDatabase(SQLiteDatabase db, boolean internal, 540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int fromVersion, int toVersion) { 541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // sanity checks 543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (toVersion != DATABASE_VERSION) { 544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Illegal update request. Got " + toVersion + ", expected " + 545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DATABASE_VERSION); 546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (fromVersion > toVersion) { 54895ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen Log.e(TAG, "Illegal update request: can't downgrade from " + fromVersion + 549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " to " + toVersion + ". Did you forget to wipe data?"); 550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 553d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // Revisions 84-86 were a failed attempt at supporting the "album artist" id3 tag. 554acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // We can't downgrade from those revisions, so start over. 555022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // (the initial change to do this was wrong, so now we actually need to start over 556022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // if the database version is 84-89) 557bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Post-gingerbread, revisions 91-94 were broken in a way that is not easy to repair. 558bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // However version 91 was reused in a divergent development path for gingerbread, 559bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // so we need to support upgrades from 91. 560bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Therefore we will only force a reset for versions 92 - 94. 561d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (fromVersion < 63 || (fromVersion >= 84 && fromVersion <= 89) || 562bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin (fromVersion >= 92 && fromVersion <= 94)) { 563acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen fromVersion = 63; 564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Drop everything and start over. 565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.i(TAG, "Upgrading media database from version " + 566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fromVersion + " to " + toVersion + ", which will destroy all old data"); 567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS images"); 568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS images_cleanup"); 569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS thumbnails"); 570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS thumbnails_cleanup"); 571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_meta"); 572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS artists"); 573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS albums"); 574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS album_art"); 575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artist_info"); 576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS album_info"); 577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artists_albums_map"); 578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres"); 580702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres_map"); 581702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_genres_cleanup"); 582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists"); 583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists_map"); 584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_playlists_cleanup"); 585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup1"); 586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup2"); 587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS video"); 588702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS video_cleanup"); 589cec8df8a90209fc4df5d1ff5f02dc364d0d2edc6Mike Lockwood db.execSQL("DROP TABLE IF EXISTS objects"); 5909ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_objects_cleanup"); 5919ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_objects_cleanup"); 5929ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_objects_cleanup"); 5939ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS playlists_objects_cleanup"); 594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS images (" + 596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 600702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 603702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "picasa_id TEXT," + 606702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + 607702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "orientation INTEGER," + 611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER," + 612702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_id TEXT," + 613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_display_name TEXT" + 614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS mini_thumb_magic_index on images(mini_thumb_magic);"); 617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS images_cleanup DELETE ON images " + 619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM thumbnails WHERE image_id = old._id;" + 621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 624b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create image thumbnail table 625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS thumbnails (" + 626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "image_id INTEGER," + 629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "kind INTEGER," + 630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "width INTEGER," + 631702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "height INTEGER" + 632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS image_id_index on thumbnails(image_id);"); 635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS thumbnails_cleanup DELETE ON thumbnails " + 637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about audio files 642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_meta (" + 643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 644216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen "_data TEXT UNIQUE NOT NULL," + 645702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 646702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 647702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 649702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 650702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT NOT NULL," + 651702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title_key TEXT NOT NULL," + 652702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 653702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER," + 654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "composer TEXT," + 655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER," + 656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "track INTEGER," + // track is an integer to allow proper sorting 657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "year INTEGER CHECK(year!=0)," + 658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_ringtone INTEGER," + 659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_music INTEGER," + 660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_alarm INTEGER," + 661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_notification INTEGER" + 662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 663702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for artists 665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS artists (" + 666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER PRIMARY KEY," + 667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_key TEXT NOT NULL UNIQUE," + 668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT NOT NULL" + 669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for albums 672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS albums (" + 673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_key TEXT NOT NULL UNIQUE," + 675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT NOT NULL" + 676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS album_art (" + 679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT" + 681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 68495ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides some extra info about artists, like the number of tracks 687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and albums for this artist 688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT artist_id AS _id, artist, artist_key, " + 690acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album) AS number_of_albums, " + 691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "GROUP BY artist_key;"); 693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 694702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides extra info albums, such as the number of tracks 695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS album_info AS " + 696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT audio.album_id AS _id, album, album_key, " + 697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MIN(year) AS minyear, " + 698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MAX(year) AS maxyear, artist, artist_id, artist_key, " + 699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "count(*) AS " + MediaStore.Audio.Albums.NUMBER_OF_SONGS + 700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ",album_art._data AS album_art" + 701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " FROM audio LEFT OUTER JOIN album_art ON audio.album_id=album_art.album_id" + 702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " WHERE is_music=1 GROUP BY audio.album_id;"); 703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 704acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 705acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 706acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 707acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 708acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /* 710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Only external media volumes can handle genres, playlists, etc. 711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!internal) { 713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio file is deleted 714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON audio_meta " + 715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE audio_id = old._id;" + 717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE audio_id = old._id;" + 718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio genre definitions 721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres (" + 722702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 723702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL" + 724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contiains mappings between audio genres and audio files 727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres_map (" + 728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "genre_id INTEGER NOT NULL" + 731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio genre is delete 734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_genres_cleanup DELETE ON audio_genres " + 735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE genre_id = old._id;" + 737702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio playlist definitions 740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists (" + 741702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 742702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + // _data is path for file based playlists, or null 743702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL," + 744702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 745702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER" + 746702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 747702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 748702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains mappings between audio playlists and audio files 749702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists_map (" + 750702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 751702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "playlist_id INTEGER NOT NULL," + 753702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "play_order INTEGER NOT NULL" + 754702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 755702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio playlist is deleted 757702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_playlists_cleanup DELETE ON audio_playlists " + 758702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE playlist_id = old._id;" + 760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 762702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 763702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art table entry when an album is deleted 764702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup1 DELETE ON albums " + 765702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 766702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM album_art WHERE album_id = old.album_id;" + 767702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 768702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 769702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art when an album is deleted 770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup2 DELETE ON album_art " + 771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 772702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 773702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 774702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 775702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about video files 777702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS video (" + 778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 779702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT NOT NULL," + 780702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT," + 788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT," + 789702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "resolution TEXT," + 790702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 791702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + // for YouTube videos 792702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "tags TEXT," + // for YouTube videos 793702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "category TEXT," + // for YouTube videos 794702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "language TEXT," + // for YouTube videos 795702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_data TEXT," + 796702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 797702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 798702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 799702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER" + 800702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS video_cleanup DELETE ON video " + 803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 805702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 806702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // At this point the database is at least at schema version 63 (it was 809702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // either created at version 63 by the code above, or was already at 810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // version 63 or later) 811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 64) { 813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 64 814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS sort_index on images(datetaken ASC, _id ASC);"); 815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 817acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 818acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.0 shipped with database version 64 819acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 820acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 65) { 822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 65 823702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS titlekey_index on audio_meta(title_key);"); 824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 826403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 66, originally we updateBucketNames(db, "images"), 827403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // but we need to do it in version 89 and therefore save the update here. 828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 829702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 67) { 830702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the indices that update the database to schema version 67 831702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS albumkey_index on albums(album_key);"); 832702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS artistkey_index on artists(artist_key);"); 833702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 834702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 835702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 68) { 836702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bucket_id and bucket_display_name columns for the video table. 837702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_id TEXT;"); 838702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_display_name TEXT"); 839403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 840403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 68, originally we updateBucketNames(db, "video"), 841403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // but we need to do it in version 89 and therefore save the update here. 842702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 843702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 844702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 69) { 845702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDisplayName(db, "images"); 846702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 847702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 848702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 70) { 849702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bookmark column for the video table. 850702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bookmark INTEGER;"); 851702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 85295ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 853702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 71) { 854702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // There is no change to the database schema, however a code change 855702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // fixed parsing of metadata for certain files bought from the 856702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // iTunes music store, so we want to rescan files that might need it. 857702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We do this by clearing the modification date in the database for 858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // those files, so that the media scanner will see them as updated 859702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and rescan them. 860702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET date_modified=0 WHERE _id IN (" + 861702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _id FROM audio where mime_type='audio/mp4' AND " + 862e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "artist='" + MediaStore.UNKNOWN_STRING + "' AND " + 863e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "album='" + MediaStore.UNKNOWN_STRING + "'" + 864702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 865702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 86695ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 867702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 72) { 868702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create is_podcast and bookmark columns for the audio table. 869702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN is_podcast INTEGER;"); 870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE _data LIKE '%/podcasts/%';"); 871702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_music=0 WHERE is_podcast=1" + 872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _data NOT LIKE '%/music/%';"); 873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN bookmark INTEGER;"); 874702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 875702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // New columns added to tables aren't visible in views on those tables 876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // without opening and closing the database (or using the 'vacuum' command, 877702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // which we can't do here because all this code runs inside a transaction). 878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // To work around this, we drop and recreate the affected view and trigger. 879702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 88195ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 882acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 883acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.5 shipped with database version 72 884acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 885acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 8868d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen if (fromVersion < 73) { 8878d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // There is no change to the database schema, but we now do case insensitive 8888d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // matching of folder names when determining whether something is music, a 8898d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // ringtone, podcast, etc, so we might need to reclassify some files. 8908d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_music=1 WHERE is_music=0 AND " + 8918d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/music/%';"); 8928d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_ringtone=1 WHERE is_ringtone=0 AND " + 8938d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/ringtones/%';"); 8948d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_notification=1 WHERE is_notification=0 AND " + 8958d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/notifications/%';"); 8968d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_alarm=1 WHERE is_alarm=0 AND " + 8978d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/alarms/%';"); 8988d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE is_podcast=0 AND " + 8998d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/podcasts/%';"); 9008d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen } 901a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 902a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (fromVersion < 74) { 903a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // This view is used instead of the audio view by the union below, to force 904a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // sqlite to use the title_key index. This greatly reduces memory usage 905a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // (no separate copy pass needed for sorting, which could cause errors on 906a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // large datasets) and improves speed (by about 35% on a large dataset) 907a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS searchhelpertitle AS SELECT * FROM audio " + 908a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "ORDER BY title_key;"); 909a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 910a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS search AS " + 911a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 912a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'artist' AS mime_type," + 913a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 914a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS album," + 915a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 916a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text1," + 917a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS text2," + 918a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_albums AS data1," + 919a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_tracks AS data2," + 920a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key AS match," + 921a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/artists/'||_id AS suggest_intent_data," + 922a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "1 AS grouporder " + 923e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM artist_info WHERE (artist!='" + MediaStore.UNKNOWN_STRING + "') " + 924a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 925a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 926a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'album' AS mime_type," + 927a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 928a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 929a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 930a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album AS text1," + 931a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 932a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 933a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 934a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key AS match," + 935a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/albums/'||_id AS suggest_intent_data," + 936a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "2 AS grouporder " + 937e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM album_info WHERE (album!='" + MediaStore.UNKNOWN_STRING + "') " + 938a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 939a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT searchhelpertitle._id AS _id," + 940a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "mime_type," + 941a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 942a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 943a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title," + 944a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title AS text1," + 945a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 946a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 947a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 948a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key||' '||title_key AS match," + 949a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/media/'||searchhelpertitle._id AS " + 950a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "suggest_intent_data," + 951a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "3 AS grouporder " + 952a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "FROM searchhelpertitle WHERE (title != '') " 953a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ); 954a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } 95559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 95659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (fromVersion < 75) { 95795ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen // Force a rescan of the audio entries so we can apply the new logic to 95859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // distinguish same-named albums. 95959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 96059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("DELETE FROM albums"); 96159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 96215d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen 96315d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen if (fromVersion < 76) { 96415d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // We now ignore double quotes when building the key, so we have to remove all of them 96515d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // from existing keys. 96615d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE audio_meta SET title_key=" + 96715d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(title_key,x'081D08C29F081D',x'081D') " + 96815d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE title_key LIKE '%'||x'081D08C29F081D'||'%';"); 96915d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE albums SET album_key=" + 97015d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(album_key,x'081D08C29F081D',x'081D') " + 97115d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE album_key LIKE '%'||x'081D08C29F081D'||'%';"); 97215d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE artists SET artist_key=" + 97315d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(artist_key,x'081D08C29F081D',x'081D') " + 97415d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE artist_key LIKE '%'||x'081D08C29F081D'||'%';"); 97515d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen } 976b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 977acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 978acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.6 shipped with database version 76 979acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 980acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 981b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (fromVersion < 77) { 982b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create video thumbnail table 983b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TABLE IF NOT EXISTS videothumbnails (" + 984b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_id INTEGER PRIMARY KEY," + 985b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_data TEXT," + 986b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "video_id INTEGER," + 987b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "kind INTEGER," + 988b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "width INTEGER," + 989b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "height INTEGER" + 990b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ");"); 991b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 992b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE INDEX IF NOT EXISTS video_id_index on videothumbnails(video_id);"); 993b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 994b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TRIGGER IF NOT EXISTS videothumbnails_cleanup DELETE ON videothumbnails " + 995b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "BEGIN " + 996b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "SELECT _DELETE_FILE(old._data);" + 997b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "END"); 998b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 9991769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen 1000acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 1001acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.0 and 2.0.1 shipped with database version 77 1002acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 1003acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 10041769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen if (fromVersion < 78) { 1005044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force a rescan of the video entries so we can update 10061769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen // latest changed DATE_TAKEN units (in milliseconds). 10071769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen db.execSQL("UPDATE video SET date_modified=0;"); 10081769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen } 1009268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 1010acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 1011acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.1 shipped with database version 78 1012acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 1013acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 1014268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (fromVersion < 79) { 1015268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move /sdcard/albumthumbs to 1016268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // /sdcard/Android/data/com.android.providers.media/albumthumbs, 1017268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // and update the database accordingly 1018268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 10199541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood String oldthumbspath = mMediaStoragePath + "/albumthumbs"; 10209541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood String newthumbspath = mMediaStoragePath + "/" + ALBUM_THUMB_FOLDER; 1021268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File thumbsfolder = new File(oldthumbspath); 1022268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (thumbsfolder.exists()) { 1023268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move folder to its new location 1024268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File newthumbsfolder = new File(newthumbspath); 1025268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen newthumbsfolder.getParentFile().mkdirs(); 1026268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if(thumbsfolder.renameTo(newthumbsfolder)) { 1027268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // update the database 1028268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen db.execSQL("UPDATE album_art SET _data=REPLACE(_data, '" + 1029268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen oldthumbspath + "','" + newthumbspath + "');"); 1030268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 1031268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 1032268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 1033044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen 1034044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen if (fromVersion < 80) { 1035044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force rescan of image entries to update DATE_TAKEN as UTC timestamp. 1036044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen db.execSQL("UPDATE images SET date_modified=0;"); 1037044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen } 10380ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 1039166a4e3cc66a645cc5e11d2f06d059512def0aceMarco Nelissen if (fromVersion < 81 && !internal) { 10400ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete entries starting with /mnt/sdcard. This is for the benefit 10410ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // of users running builds between 2.0.1 and 2.1 final only, since 10420ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // users updating from 2.0 or earlier will not have such entries. 10430ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 10440ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // First we need to update the _data fields in the affected tables, since 10450ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // otherwise deleting the entries will also delete the underlying files 10460ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // (via a trigger), and we want to keep them. 10470ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 10480ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 10490ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 10500ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 10510ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 10520ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 1053216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("UPDATE audio_meta SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 10540ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Once the paths have been renamed, we can safely delete the entries 10550ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_playlists WHERE _data IS '////';"); 10560ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM images WHERE _data IS '////';"); 10570ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM video WHERE _data IS '////';"); 10580ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM videothumbnails WHERE _data IS '////';"); 10590ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM thumbnails WHERE _data IS '////';"); 10600ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_meta WHERE _data IS '////';"); 10610ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM album_art WHERE _data IS '////';"); 10620ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 10630ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // rename existing entries starting with /sdcard to /mnt/sdcard 10640ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta" + 10650ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 10660ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists" + 10670ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 10680ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images" + 10690ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 10700ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video" + 10710ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 10720ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails" + 10730ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 10740ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails" + 10750ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 10760ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art" + 10770ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 10780ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 10790ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete albums and artists, then clear the modification time on songs, which 10800ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // will cause the media scanner to rescan everything, rebuilding the artist and 10810ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // album tables along the way, while preserving playlists. 10820ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // We need this rescan because ICU also changed, and now generates different 10830ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // collation keys 10840ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from albums"); 10850ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from artists"); 10860ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 10870ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen } 108884403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen 108984403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen if (fromVersion < 82) { 1090acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // recreate this view with the correct "group by" specifier 109184403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("DROP VIEW IF EXISTS artist_info"); 109284403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 109384403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "SELECT artist_id AS _id, artist, artist_key, " + 1094acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album_key) AS number_of_albums, " + 109584403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 109684403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "GROUP BY artist_key;"); 109784403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen } 1098216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 1099acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* we skipped over version 83, and reverted versions 84, 85 and 86 */ 1100ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen 1101ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen if (fromVersion < 87) { 1102ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // The fastscroll thumb needs an index on the strings being displayed, 1103ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // otherwise the queries it does to determine the correct position 1104ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // becomes really inefficient 1105022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS title_idx on audio_meta(title);"); 1106022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_idx on artists(artist);"); 1107022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_idx on albums(album);"); 1108ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } 1109216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 1110acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen if (fromVersion < 88) { 1111acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // Clean up a few more things from versions 84/85/86, and recreate 1112acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // the few things worth keeping from those changes. 1113acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update1;"); 1114acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update2;"); 1115acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update3;"); 1116acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update4;"); 1117acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update1;"); 1118acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update2;"); 1119acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update3;"); 1120acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update4;"); 112116dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP VIEW IF EXISTS album_artists;"); 1122acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_id_idx on audio_meta(album_id);"); 1123acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_id_idx on audio_meta(artist_id);"); 1124acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 1125acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 1126acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 1127acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 1128acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen } 1129403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 1130fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // In version 89, originally we updateBucketNames(db, "images") and 1131fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // updateBucketNames(db, "video"), but in version 101 we now updateBucketNames 1132fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // for all files and therefore can save the update here. 1133b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 1134b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (fromVersion < 91) { 1135bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Never query by mini_thumb_magic_index 1136bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("DROP INDEX IF EXISTS mini_thumb_magic_index"); 1137bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin 1138bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // sort the items by taken date in each bucket 1139bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("CREATE INDEX IF NOT EXISTS image_bucket_index ON images(bucket_id, datetaken)"); 1140bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("CREATE INDEX IF NOT EXISTS video_bucket_index ON video(bucket_id, datetaken)"); 1141bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin } 1142bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin 1143afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // versions 92 - 98 were work in progress on MTP obsoleted by version 99 114486f165b636baa8c6e0f4568fb07699ff5cfbcf8aMarco Nelissen if (fromVersion < 92) { 114586f165b636baa8c6e0f4568fb07699ff5cfbcf8aMarco Nelissen // Delete albums and artists, then clear the modification time on songs, which 114686f165b636baa8c6e0f4568fb07699ff5cfbcf8aMarco Nelissen // will cause the media scanner to rescan everything, rebuilding the artist and 114786f165b636baa8c6e0f4568fb07699ff5cfbcf8aMarco Nelissen // album tables along the way, while preserving playlists. 114886f165b636baa8c6e0f4568fb07699ff5cfbcf8aMarco Nelissen // We need this rescan because ICU also changed, and now generates different 114986f165b636baa8c6e0f4568fb07699ff5cfbcf8aMarco Nelissen // collation keys 115086f165b636baa8c6e0f4568fb07699ff5cfbcf8aMarco Nelissen db.execSQL("DELETE from albums"); 115186f165b636baa8c6e0f4568fb07699ff5cfbcf8aMarco Nelissen db.execSQL("DELETE from artists"); 115286f165b636baa8c6e0f4568fb07699ff5cfbcf8aMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 115386f165b636baa8c6e0f4568fb07699ff5cfbcf8aMarco Nelissen } 1154b0344f3357caabb0c9a34a3d1dc3899f0e6a5d74Jason Chen 1155afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (fromVersion < 99) { 1156afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Remove various stages of work in progress for MTP support 1157afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS objects"); 1158afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS files"); 115916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_objects_cleanup;"); 116016dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_objects_cleanup;"); 116116dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_objects_cleanup;"); 116216dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS playlists_objects_cleanup;"); 1163afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_images;"); 1164afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_audio;"); 1165afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_video;"); 1166afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_playlists;"); 1167afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS media_cleanup;"); 1168afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1169afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Create a new table to manage all files in our storage. 1170afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // This contains a union of all the columns from the old 1171afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // images, audio_meta, videos and audio_playlist tables. 1172afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TABLE files (" + 117300a22306f6c99d1f1b4424f8f6a1cad8fb332d85Ray Chen "_id INTEGER PRIMARY KEY AUTOINCREMENT," + 1174afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data TEXT," + // this can be null for playlists 1175afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_size INTEGER," + 1176afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "format INTEGER," + 1177afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "parent INTEGER," + 1178afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_added INTEGER," + 1179afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_modified INTEGER," + 1180afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mime_type TEXT," + 1181afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "title TEXT," + 1182afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "description TEXT," + 1183afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_display_name TEXT," + 1184afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1185afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for images 1186afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "picasa_id TEXT," + 1187afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "orientation INTEGER," + 1188afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1189afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for images and video 1190afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "latitude DOUBLE," + 1191afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "longitude DOUBLE," + 1192afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "datetaken INTEGER," + 1193afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mini_thumb_magic INTEGER," + 1194afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bucket_id TEXT," + 1195afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bucket_display_name TEXT," + 1196afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "isprivate INTEGER," + 1197afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1198afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for audio 1199afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "title_key TEXT," + 1200afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "artist_id INTEGER," + 1201afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "album_id INTEGER," + 1202afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "composer TEXT," + 1203afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "track INTEGER," + 1204afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "year INTEGER CHECK(year!=0)," + 1205afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_ringtone INTEGER," + 1206afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_music INTEGER," + 1207afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_alarm INTEGER," + 1208afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_notification INTEGER," + 1209afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_podcast INTEGER," + 1210afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1211afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for audio and video 1212afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "duration INTEGER," + 1213afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bookmark INTEGER," + 1214afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1215afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for video 1216afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "artist TEXT," + 1217afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "album TEXT," + 1218afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "resolution TEXT," + 1219afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "tags TEXT," + 1220afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "category TEXT," + 1221afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "language TEXT," + 1222afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mini_thumb_data TEXT," + 1223afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1224afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for playlists 1225afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "name TEXT," + 1226afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1227afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // media_type is used by the views to emulate the old 1228afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // images, audio_meta, videos and audio_playlist tables. 1229afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "media_type INTEGER," + 1230afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1231afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Value of _id from the old media table. 1232afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Used only for updating other tables during database upgrade. 1233afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "old_id INTEGER" + 1234afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood ");"); 1235afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX path_index ON files(_data);"); 1236afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX media_type_index ON files(media_type);"); 1237afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1238afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Copy all data from our obsolete tables to the new files table 1239afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("INSERT INTO files (" + IMAGE_COLUMNS + ",old_id,media_type) SELECT " 1240afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + IMAGE_COLUMNS + ",_id," + FileColumns.MEDIA_TYPE_IMAGE + " FROM images;"); 1241805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen db.execSQL("INSERT INTO files (" + AUDIO_COLUMNSv99 + ",old_id,media_type) SELECT " 1242805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen + AUDIO_COLUMNSv99 + ",_id," + FileColumns.MEDIA_TYPE_AUDIO + " FROM audio_meta;"); 1243afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("INSERT INTO files (" + VIDEO_COLUMNS + ",old_id,media_type) SELECT " 1244afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + VIDEO_COLUMNS + ",_id," + FileColumns.MEDIA_TYPE_VIDEO + " FROM video;"); 124516dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood if (!internal) { 1246afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("INSERT INTO files (" + PLAYLIST_COLUMNS + ",old_id,media_type) SELECT " 1247afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + PLAYLIST_COLUMNS + ",_id," + FileColumns.MEDIA_TYPE_PLAYLIST 1248afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + " FROM audio_playlists;"); 1249afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 125016dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood 1251afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Delete the old tables 1252afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS images"); 1253afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS audio_meta"); 1254afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS video"); 1255afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS audio_playlists"); 125616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood 1257afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Create views to replace our old tables 1258afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE VIEW images AS SELECT _id," + IMAGE_COLUMNS + 1259afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1260afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_IMAGE + ";"); 1261805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen// audio_meta will be created below for schema 100 1262805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen// db.execSQL("CREATE VIEW audio_meta AS SELECT _id," + AUDIO_COLUMNSv99 + 1263805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen// " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1264805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen// + FileColumns.MEDIA_TYPE_AUDIO + ";"); 1265afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE VIEW video AS SELECT _id," + VIDEO_COLUMNS + 1266afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1267afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_VIDEO + ";"); 1268afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (!internal) { 1269afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE VIEW audio_playlists AS SELECT _id," + PLAYLIST_COLUMNS + 1270afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1271afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_PLAYLIST + ";"); 127216dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood } 127336339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1274afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // update the image_id column in the thumbnails table. 1275afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE thumbnails SET image_id = (SELECT _id FROM files " 1276afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = thumbnails.image_id AND files.media_type = " 1277afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_IMAGE + ");"); 127836339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1279afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (!internal) { 1280afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // update audio_id in the audio_genres_map and audio_playlists_map tables. 1281afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE audio_genres_map SET audio_id = (SELECT _id FROM files " 1282afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = audio_genres_map.audio_id AND files.media_type = " 1283afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_AUDIO + ");"); 1284afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE audio_playlists_map SET audio_id = (SELECT _id FROM files " 1285afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = audio_playlists_map.audio_id " 1286afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "AND files.media_type = " + FileColumns.MEDIA_TYPE_AUDIO + ");"); 1287afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 1288afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1289afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // update video_id in the videothumbnails table. 1290afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE videothumbnails SET video_id = (SELECT _id FROM files " 1291afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = videothumbnails.video_id AND files.media_type = " 1292afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_VIDEO + ");"); 1293afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1294afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // update indices to work on the files table 1295afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS title_idx"); 1296afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS album_id_idx"); 1297afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS image_bucket_index"); 1298afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS video_bucket_index"); 1299afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS sort_index"); 1300afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS titlekey_index"); 1301afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS artist_id_idx"); 1302afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX title_idx ON files(title);"); 1303afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX album_id_idx ON files(album_id);"); 1304afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX bucket_index ON files(bucket_id, datetaken);"); 1305afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX sort_index ON files(datetaken ASC, _id ASC);"); 1306afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX titlekey_index ON files(title_key);"); 1307afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX artist_id_idx ON files(artist_id);"); 1308afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1309afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Recreate triggers for our obsolete tables on the new files table 1310afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_cleanup"); 1311afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 1312afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_cleanup"); 1313afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_playlists_cleanup"); 1314afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_delete"); 131536339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1316afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS images_cleanup DELETE ON files " + 1317afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_IMAGE + " " + 131836339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "BEGIN " + 1319afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM thumbnails WHERE image_id = old._id;" + 1320afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT _DELETE_FILE(old._data);" + 132136339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "END"); 132236339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1323afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS video_cleanup DELETE ON files " + 132449dea76284f7693ba452c05cfd59c1d9c9584343Ray Chen "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_VIDEO + " " + 132536339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "BEGIN " + 1326afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT _DELETE_FILE(old._data);" + 132736339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "END"); 132836339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1329afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (!internal) { 1330afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON files " + 1331afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_AUDIO + " " + 1332afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "BEGIN " + 1333afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM audio_genres_map WHERE audio_id = old._id;" + 1334afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM audio_playlists_map WHERE audio_id = old._id;" + 1335afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "END"); 1336afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1337afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_playlists_cleanup DELETE ON files " + 1338afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_PLAYLIST + " " + 1339afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "BEGIN " + 1340afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM audio_playlists_map WHERE playlist_id = old._id;" + 1341afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT _DELETE_FILE(old._data);" + 1342afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "END"); 1343afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1344afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_delete INSTEAD OF DELETE ON audio " + 134536339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "BEGIN " + 1346afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE from files where _id=old._id;" + 1347afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE from audio_playlists_map where audio_id=old._id;" + 1348afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE from audio_genres_map where audio_id=old._id;" + 134936339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "END"); 135036339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood } 135136339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood } 135236339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1353805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen if (fromVersion < 100) { 1354805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen db.execSQL("ALTER TABLE files ADD COLUMN album_artist TEXT;"); 1355805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen db.execSQL("DROP VIEW IF EXISTS audio_meta;"); 1356805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen db.execSQL("CREATE VIEW audio_meta AS SELECT _id," + AUDIO_COLUMNSv100 + 1357805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1358805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 1359805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 1360805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 1361805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen } 1362805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen 1363fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood if (fromVersion < 300) { 1364fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // we now compute bucket and display names for all files to avoid problems with files 1365fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // that the media scanner might not recognize as images or videos 1366fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood updateBucketNames(db, "files"); 1367fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood } 1368fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood 1369acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sanityCheck(db, fromVersion); 13701d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen } 13711d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen 13721d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen /** 1373216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * Perform a simple sanity check on the database. Currently this tests 1374216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * whether all the _data entries in audio_meta are unique 1375216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen */ 1376216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen private static void sanityCheck(SQLiteDatabase db, int fromVersion) { 1377216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c1 = db.query("audio_meta", new String[] {"count(*)"}, 1378216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 1379216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c2 = db.query("audio_meta", new String[] {"count(distinct _data)"}, 1380216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 1381216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.moveToFirst(); 1382216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.moveToFirst(); 1383216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num1 = c1.getInt(0); 1384216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num2 = c2.getInt(0); 1385216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.close(); 1386216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.close(); 1387216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (num1 != num2) { 1388216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Log.e(TAG, "audio_meta._data column is not unique while upgrading" + 1389216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen " from schema " +fromVersion + " : " + num1 +"/" + num2); 1390216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen // Delete all audio_meta rows so they will be rebuilt by the media scanner 1391216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("DELETE FROM audio_meta;"); 1392216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 1393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void recreateAudioView(SQLiteDatabase db) { 1396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides a unified audio/artist/album info view. 1397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note that views are read-only, so we define a trigger to allow deletes. 1398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS audio"); 1399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_delete"); 1400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS audio as SELECT * FROM audio_meta " + 1401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN artists ON audio_meta.artist_id=artists.artist_id " + 1402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN albums ON audio_meta.album_id=albums.album_id;"); 1403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_delete INSTEAD OF DELETE ON audio " + 1405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 1406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_meta where _id=old._id;" + 1407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_playlists_map where audio_id=old._id;" + 1408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_genres_map where audio_id=old._id;" + 1409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 1410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 141195ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 1412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the bucket_id and 1414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * bucket_display_name columns are correct. 1415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 1416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 1417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateBucketNames(SQLiteDatabase db, String tableName) { 1419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Rebuild the bucket_display_name column using the natural case rather than lower case. 1420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA}; 1423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 1424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 1427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 1429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(); 1430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 1431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int rowId = cursor.getInt(idColumnIndex); 1432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(tableName, values, "_id=" + rowId, null); 1433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the 1445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * display name column has a value. 1446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 1447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 1448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDisplayName(SQLiteDatabase db, String tableName) { 1450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Fill in default values for null displayName values 1451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA, MediaColumns.DISPLAY_NAME}; 1454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 1455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 1458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int displayNameIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME); 1459702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(); 1460702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String displayName = cursor.getString(displayNameIndex); 1462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (displayName == null) { 1463702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 1464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.clear(); 1465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 1466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int rowId = cursor.getInt(idColumnIndex); 1467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(tableName, values, "_id=" + rowId, null); 1468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the bucked id name and bucket display name are updated. 1481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeBucketValues(String data, ContentValues values) { 1485d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood data = mediaToExternalPath(data); 1486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File parentFile = new File(data).getParentFile(); 1487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (parentFile == null) { 1488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project parentFile = new File("/"); 1489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Lowercase the path for hashing. This avoids duplicate buckets if the 1492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // filepath case is changed externally. 1493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Keep the original case for display. 1494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path = parentFile.toString().toLowerCase(); 1495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = parentFile.getName(); 1496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note: the BUCKET_ID and BUCKET_DISPLAY_NAME attributes are spelled the 1498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // same for both images and video. However, for backwards-compatibility reasons 1499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // there is no common base class. We use the ImageColumns version here 1500d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood values.put(ImageColumns.BUCKET_ID, path.hashCode()); 1501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(ImageColumns.BUCKET_DISPLAY_NAME, name); 1502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1506702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the display name is updated. 1507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeDisplayName(String data, ContentValues values) { 1510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = (data == null ? "" : data.toString()); 1511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int idx = s.lastIndexOf('/'); 1512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (idx >= 0) { 1513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = s.substring(idx + 1); 1514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("_display_name", s); 1516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1518b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen /** 1519498b62c2912302a23532c73a028a7684c5df33caRay Chen * Copy taken time from date_modified if we lost the original value (e.g. after factory reset) 1520498b62c2912302a23532c73a028a7684c5df33caRay Chen * This works for both video and image tables. 1521b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * 1522b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * @param values the content values, where taken time is updated. 1523b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen */ 1524b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen private static void computeTakenTime(ContentValues values) { 1525b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (! values.containsKey(Images.Media.DATE_TAKEN)) { 1526b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // This only happens when MediaScanner finds an image file that doesn't have any useful 1527b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // reference to get this value. (e.g. GPSTimeStamp) 1528498b62c2912302a23532c73a028a7684c5df33caRay Chen Long lastModified = values.getAsLong(MediaColumns.DATE_MODIFIED); 1529b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (lastModified != null) { 1530b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen values.put(Images.Media.DATE_TAKEN, lastModified * 1000); 1531b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1532b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1533b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1534b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen 1535b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen /** 1536b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * This method blocks until thumbnail is ready. 1537b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * 1538b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @param thumbUri 1539b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @return 1540b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen */ 1541b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean waitForThumbnailReady(Uri origUri) { 1542b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Cursor c = this.query(origUri, new String[] { ImageColumns._ID, ImageColumns.DATA, 1543b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ImageColumns.MINI_THUMB_MAGIC}, null, null, null); 1544b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c == null) return false; 1545b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1546b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean result = false; 1547b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1548b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c.moveToFirst()) { 1549e263c2a4b880ef8a5314bb4379c74bf5f9292bd0Ray Chen long id = c.getLong(0); 1550b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String path = c.getString(1); 1551b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen long magic = c.getLong(2); 1552d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood path = mediaToExternalPath(path); 1553b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 15549299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest req = requestMediaThumbnail(path, origUri, 15559299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest.PRIORITY_HIGH, magic); 15569299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req == null) { 15579299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen return false; 15589299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 15599299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen synchronized (req) { 15609299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen try { 15619299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen while (req.mState == MediaThumbRequest.State.WAIT) { 15629299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen req.wait(); 156320434e032e498b716f87cce2f23dd646819218bfRay Chen } 15649299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } catch (InterruptedException e) { 15659299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen Log.w(TAG, e); 15669299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 15679299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req.mState == MediaThumbRequest.State.DONE) { 15689299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen result = true; 1569b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1570b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1571b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1572b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen c.close(); 1573b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1574b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return result; 1575b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1576b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1577e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen private boolean matchThumbRequest(MediaThumbRequest req, int pid, long id, long gid, 1578e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo) { 1579e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllOrigId = (id == -1); 1580e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllGroupId = (gid == -1); 1581e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen return (req.mCallingPid == pid) && 1582e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllGroupId || req.mGroupId == gid) && 1583e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllOrigId || req.mOrigId == id) && 1584e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (req.mIsVideo == isVideo); 1585e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 1586e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 1587b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean queryThumbnail(SQLiteQueryBuilder qb, Uri uri, String table, 1588b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String column, boolean hasThumbnailId) { 1589b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.setTables(table); 1590b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (hasThumbnailId) { 1591b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // For uri dispatched to this method, the 4th path segment is always 1592b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // the thumbnail id. 1593b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere("_id = " + uri.getPathSegments().get(3)); 1594b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // client already knows which thumbnail it wants, bypass it. 1595b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1596b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1597b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String origId = uri.getQueryParameter("orig_id"); 1598b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // We can't query ready_flag unless we know original id 1599b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId == null) { 1600b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // this could be thumbnail query for other purpose, bypass it. 1601b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1602b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1603b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1604b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean needBlocking = "1".equals(uri.getQueryParameter("blocking")); 160520434e032e498b716f87cce2f23dd646819218bfRay Chen boolean cancelRequest = "1".equals(uri.getQueryParameter("cancel")); 1606e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Uri origUri = uri.buildUpon().encodedPath( 1607e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen uri.getPath().replaceFirst("thumbnails", "media")) 1608e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen .appendPath(origId).build(); 1609b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1610b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (needBlocking && !waitForThumbnailReady(origUri)) { 161120434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original media doesn't exist or it's canceled."); 1612b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return false; 161320434e032e498b716f87cce2f23dd646819218bfRay Chen } else if (cancelRequest) { 1614e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen String groupId = uri.getQueryParameter("group_id"); 1615e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo = "video".equals(uri.getPathSegments().get(1)); 161620434e032e498b716f87cce2f23dd646819218bfRay Chen int pid = Binder.getCallingPid(); 161720434e032e498b716f87cce2f23dd646819218bfRay Chen long id = -1; 1618e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen long gid = -1; 1619e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 162020434e032e498b716f87cce2f23dd646819218bfRay Chen try { 162120434e032e498b716f87cce2f23dd646819218bfRay Chen id = Long.parseLong(origId); 1622e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen gid = Long.parseLong(groupId); 162320434e032e498b716f87cce2f23dd646819218bfRay Chen } catch (NumberFormatException ex) { 162420434e032e498b716f87cce2f23dd646819218bfRay Chen // invalid cancel request 162520434e032e498b716f87cce2f23dd646819218bfRay Chen return false; 162620434e032e498b716f87cce2f23dd646819218bfRay Chen } 1627e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 162820434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mMediaThumbQueue) { 1629e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (mCurrentThumbRequest != null && 1630e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen matchThumbRequest(mCurrentThumbRequest, pid, id, gid, isVideo)) { 163120434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 163220434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.CANCEL; 163320434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 163420434e032e498b716f87cce2f23dd646819218bfRay Chen } 163520434e032e498b716f87cce2f23dd646819218bfRay Chen } 163620434e032e498b716f87cce2f23dd646819218bfRay Chen for (MediaThumbRequest mtq : mMediaThumbQueue) { 1637e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (matchThumbRequest(mtq, pid, id, gid, isVideo)) { 163820434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mtq) { 163920434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.mState = MediaThumbRequest.State.CANCEL; 164020434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.notifyAll(); 164120434e032e498b716f87cce2f23dd646819218bfRay Chen } 164220434e032e498b716f87cce2f23dd646819218bfRay Chen 164320434e032e498b716f87cce2f23dd646819218bfRay Chen mMediaThumbQueue.remove(mtq); 164420434e032e498b716f87cce2f23dd646819218bfRay Chen } 164520434e032e498b716f87cce2f23dd646819218bfRay Chen } 164620434e032e498b716f87cce2f23dd646819218bfRay Chen } 1647b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1648b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1649b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId != null) { 1650b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere(column + " = " + origId); 1651b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1652b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1653b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1654b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen @SuppressWarnings("fallthrough") 1655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Cursor query(Uri uri, String[] projectionIn, String selection, 1657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] selectionArgs, String sort) { 1658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int table = URI_MATCHER.match(uri); 1659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 166001a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // Log.v(TAG, "query: uri="+uri+", selection="+selection); 1661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 1662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (table == MEDIA_SCANNER) { 1663702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 1664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 1665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a cursor to return volume currently being scanned by the media scanner 16670027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {MediaStore.MEDIA_SCANNER_VOLUME}); 16680027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new String[] {mMediaScannerVolume}); 16690027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 1670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 16730027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // Used temporarily (until we have unique media IDs) to get an identifier 16740027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // for the current sd card, so that the music app doesn't have to use the 16750027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // non-public getFatVolumeId method 16760027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen if (table == FS_ID) { 16770027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {"fsid"}); 16780027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new Integer[] {mVolumeId}); 16790027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 16800027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen } 16810027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 1682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String groupBy = null; 1683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 1684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 1685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 1686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getReadableDatabase(); 1688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 16894574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit = uri.getQueryParameter("limit"); 1690c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String filter = uri.getQueryParameter("filter"); 1691c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String [] keywords = null; 1692c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (filter != null) { 1693c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen filter = Uri.decode(filter).trim(); 1694c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (!TextUtils.isEmpty(filter)) { 1695c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String [] searchWords = filter.split(" "); 1696c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen keywords = new String[searchWords.length]; 1697c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen Collator col = Collator.getInstance(); 1698c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen col.setStrength(Collator.PRIMARY); 1699c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; i < searchWords.length; i++) { 1700c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String key = MediaStore.Audio.keyFor(searchWords[i]); 1701c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen key = key.replace("\\", "\\\\"); 1702c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen key = key.replace("%", "\\%"); 1703c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen key = key.replace("_", "\\_"); 1704c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen keywords[i] = key; 1705c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1706c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1707c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1708c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen 1709b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean hasThumbnailId = false; 1710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (table) { 1712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 1713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 1714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 1715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 1716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 1718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 1719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 1722702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 1723702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 1724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 1725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 1727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 1728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id = " + uri.getPathSegments().get(3)); 1729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 1732b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 1733b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 1734b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "thumbnails", "image_id", hasThumbnailId)) { 1735b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 1736b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1737702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 1740d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 1741ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.equalsIgnoreCase("is_music=1") 1742ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen || selection.equalsIgnoreCase("is_podcast=1") ) 1743c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") 1744c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && keywords != null) { 1745ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting songs"); 1746ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 1747ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 1748ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio"); 1749c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 1750c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (i > 0) { 1751c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 1752c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1753c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 1754c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 1755c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.TITLE_KEY + " LIKE '%" + 1756c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen keywords[i] + "%' ESCAPE '\\'"); 1757c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1758ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 1759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 1762702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1763702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1764702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1765702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1766702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 1767702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1768702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT genre_id FROM " + 1769702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map WHERE audio_id = " + 1770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1772702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1773702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 1774702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1775702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1777702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 1779702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1780702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT playlist_id FROM " + 1781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_playlists_map WHERE audio_id = " + 1782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 1786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1789702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1790702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 1791702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1792702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1793702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1794702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 1795702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1796702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1797702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1798702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1799702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 1800702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT audio_id FROM " + 1802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map WHERE genre_id = " + 1803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1805702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1806702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 1807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1809702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 1812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 1816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1817702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1819702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 182197e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen if (projectionIn != null) { 182297e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen for (int i = 0; i < projectionIn.length; i++) { 182397e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen if (projectionIn[i].equals("_id")) { 182497e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen projectionIn[i] = "audio_playlists_map._id AS _id"; 182597e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen } 1826702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1827702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists_map, audio"); 1829702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("audio._id = audio_id AND playlist_id = " 1830702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project + uri.getPathSegments().get(3)); 1831c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 1832c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 1833c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 1834c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 1835c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.TITLE_KEY + 1836c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen " LIKE '%" + keywords[i] + "%' ESCAPE '\\'"); 1837c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1838702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1839702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1840702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 1841702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1842702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1843702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1844702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1845702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 1846702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 1847bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin if (uri.getQueryParameter("distinct") != null) { 1848bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin qb.setDistinct(true); 1849bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin } 1850702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1851702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 1852702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 1853bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin if (uri.getQueryParameter("distinct") != null) { 1854bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin qb.setDistinct(true); 1855bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin } 1856702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1857702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1859b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 1860b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 1861b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 1862b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "videothumbnails", "video_id", hasThumbnailId)) { 1863b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 1864b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1865b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 1866b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1867702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS: 1868d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 1869ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 1870c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") 1871c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && keywords != null) { 1872ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting artists"); 1873ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 1874ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct artist_id)"; 1875ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 1876ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 1877ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("artist_info"); 1878c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 1879c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (i > 0) { 1880c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 1881c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1882c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 1883c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen " LIKE '%" + keywords[i] + "%' ESCAPE '\\'"); 1884c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1885ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 1886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID: 1889702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("artist_info"); 1890702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1892702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1893702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID_ALBUMS: 1894702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String aid = uri.getPathSegments().get(3); 1895acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.setTables("audio LEFT OUTER JOIN album_art ON" + 1896acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen " audio.album_id=album_art.album_id"); 1897acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.appendWhere("is_music=1 AND audio.album_id IN (SELECT album_id FROM " + 1898acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "artists_albums_map WHERE artist_id = " + 1899acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen aid + ")"); 1900c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 1901c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 1902c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 1903c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 1904c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen " LIKE '%" + keywords[i] + "%' ESCAPE '\\'"); 1905c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1906acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen groupBy = "audio.album_id"; 1907702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST, 1908acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "count(CASE WHEN artist_id==" + aid + " THEN 'foo' ELSE NULL END) AS " + 1909702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST); 1910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setProjectionMap(sArtistAlbumsMap); 1911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1912702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1913702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS: 1914d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 1915ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 1916c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") 1917c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && keywords != null) { 1918ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting albums"); 1919ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 1920ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct album_id)"; 1921ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 1922ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 1923ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("album_info"); 1924c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 1925c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (i > 0) { 1926c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 1927c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1928c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 1929c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 1930c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen " LIKE '%" + keywords[i] + "%' ESCAPE '\\'"); 1931c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1932ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 1933702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1934702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1935702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS_ID: 1936702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_info"); 1937702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1938702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1939702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1940702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 1941702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_art"); 1942702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("album_id=" + uri.getPathSegments().get(3)); 1943702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1944702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1945a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_LEGACY: 1946a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen Log.w(TAG, "Legacy media search Uri used. Please update your code."); 1947a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // fall through 1948a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_FANCY: 1949a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_BASIC: 1950a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen return doAudioSearch(db, qb, uri, projectionIn, selection, selectionArgs, sort, 19514574e03055af60fada50481f2b34e19a687d5866Marco Nelissen table, limit); 1952702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 195316dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES_ID: 1954e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS_ID: 1955b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood qb.appendWhere("_id=" + uri.getPathSegments().get(2)); 1956b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // fall through 195716dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES: 1958e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS: 195916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood qb.setTables("files"); 1960b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood break; 1961b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 1962e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood case MTP_OBJECT_REFERENCES: 1963e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int handle = Integer.parseInt(uri.getPathSegments().get(2)); 1964e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return getObjectReferences(db, handle); 1965e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 1966702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 1967702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unknown URL: " + uri.toString()); 1968702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1969702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 19704d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen // Log.v(TAG, "query = "+ qb.buildQuery(projectionIn, selection, selectionArgs, groupBy, null, sort, limit)); 1971702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, projectionIn, selection, 19724574e03055af60fada50481f2b34e19a687d5866Marco Nelissen selectionArgs, groupBy, null, sort, limit); 1973b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1974702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) { 1975702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.setNotificationUri(getContext().getContentResolver(), uri); 1976702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1977b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1978702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return c; 1979702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1980702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1981702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Cursor doAudioSearch(SQLiteDatabase db, SQLiteQueryBuilder qb, 1982702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri, String[] projectionIn, String selection, 19834574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String[] selectionArgs, String sort, int mode, 19844574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit) { 1985702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 198618c787fb045725bf10bf630ac0917a48def9ace5Marco Nelissen String mSearchString = uri.getPath().endsWith("/") ? "" : uri.getLastPathSegment(); 1987702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString = mSearchString.replaceAll(" ", " ").trim().toLowerCase(); 1988702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1989702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] searchWords = mSearchString.length() > 0 ? 1990702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString.split(" ") : new String[0]; 1991a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] wildcardWords = new String[searchWords.length]; 1992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Collator col = Collator.getInstance(); 1993702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project col.setStrength(Collator.PRIMARY); 1994702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = searchWords.length; 1995702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 1996702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Because we match on individual words here, we need to remove words 1997702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // like 'a' and 'the' that aren't part of the keys. 19983001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen String key = MediaStore.Audio.keyFor(searchWords[i]); 19993001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("\\", "\\\\"); 20003001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("%", "\\%"); 20013001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("_", "\\_"); 2002a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen wildcardWords[i] = 2003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project (searchWords[i].equals("a") || searchWords[i].equals("an") || 20043001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen searchWords[i].equals("the")) ? "%" : "%" + key + "%"; 2005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2007a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String where = ""; 2008a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen for (int i = 0; i < searchWords.length; i++) { 2009a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (i == 0) { 20103001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen where = "match LIKE ? ESCAPE '\\'"; 2011a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 20123001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen where += " AND match LIKE ? ESCAPE '\\'"; 2013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2014702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2015702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2016a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen qb.setTables("search"); 2017a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] cols; 2018a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (mode == AUDIO_SEARCH_FANCY) { 2019a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsFancy; 2020a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else if (mode == AUDIO_SEARCH_BASIC) { 2021a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsBasic; 2022a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 2023a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsLegacy; 2024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 20254574e03055af60fada50481f2b34e19a687d5866Marco Nelissen return qb.query(db, cols, where, wildcardWords, null, null, null, limit); 2026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2028702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2029702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String getType(Uri url) 2030702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (URI_MATCHER.match(url)) { 2032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 2033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 2035702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2036702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2037c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood case FILES_ID: 203826f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen Cursor c = null; 203926f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen try { 204026f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c = query(url, MIME_TYPE_PROJECTION, null, null, null); 204126f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null && c.getCount() == 1) { 204226f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.moveToFirst(); 204326f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen String mimeType = c.getString(1); 204426f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.deactivate(); 204526f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen return mimeType; 204626f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 204726f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } finally { 204826f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null) { 204926f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.close(); 205026f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 2051702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2053702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 2055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: 2056702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Images.Media.CONTENT_TYPE; 2057804f5fe841d4a96f9335ea60d60853352f726227Marco Nelissen case AUDIO_ALBUMART_ID: 2058702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 2059702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return "image/jpeg"; 2060702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2061702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2062702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 2063702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 2064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Media.CONTENT_TYPE; 2065702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2066702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 2067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 2068702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.CONTENT_TYPE; 2069702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 2070702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 2071702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.ENTRY_CONTENT_TYPE; 2072702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 2073702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 2074702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.CONTENT_TYPE; 2075702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2076702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 2077702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.ENTRY_CONTENT_TYPE; 2078702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2079702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2080702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Video.Media.CONTENT_TYPE; 2081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2082804f5fe841d4a96f9335ea60d60853352f726227Marco Nelissen throw new IllegalStateException("Unknown URL : " + url); 2083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2084702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2085702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2086702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Ensures there is a file in the _data column of values, if one isn't 2087702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * present a new file is created. 2088702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 2089702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param initialValues the values passed to insert by the caller 2090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the new values 2091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private ContentValues ensureFile(boolean internal, ContentValues initialValues, 2093702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String preferredExtension, String directoryName) { 2094702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values; 2095702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String file = initialValues.getAsString("_data"); 2096d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood file = mediaToExternalPath(file); 2097702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (TextUtils.isEmpty(file)) { 2098702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file = generateFileName(internal, preferredExtension, directoryName); 2099702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = new ContentValues(initialValues); 2100702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("_data", file); 2101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2102702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = initialValues; 2103702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2104702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2105702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!ensureFileExists(file)) { 2106702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unable to create new file: " + file); 2107702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return values; 2109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2111d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private void sendObjectAdded(long objectHandle) { 2112d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood IMtpService mtpService = mMtpService; 2113d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mtpService != null) { 2114d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood try { 2115d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mtpService.sendObjectAdded((int)objectHandle); 2116d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } catch (RemoteException e) { 2117d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.e(TAG, "RemoteException in sendObjectAdded", e); 2118d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2119d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2120d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2121d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 2122d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private void sendObjectRemoved(long objectHandle) { 2123d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood IMtpService mtpService = mMtpService; 2124d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mtpService != null) { 2125d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood try { 2126d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mtpService.sendObjectRemoved((int)objectHandle); 2127d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } catch (RemoteException e) { 2128d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.e(TAG, "RemoteException in sendObjectRemoved", e); 2129d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2130d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2131d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2132d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 2133702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2134702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int bulkInsert(Uri uri, ContentValues values[]) { 2135795fcfcfea623b2bd27d291eae575dfa20350e34Mike Lockwood for (int i = 0; i < values.length; i++) { 2136d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood values[i] = mediaToExternalPath(values[i]); 2137795fcfcfea623b2bd27d291eae575dfa20350e34Mike Lockwood } 2138702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 2139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == VOLUMES) { 2140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return super.bulkInsert(uri, values); 2141702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2142702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 2143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 2144702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2145702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 2146702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2147702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 2148ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 2149ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen if (match == AUDIO_PLAYLISTS_ID || match == AUDIO_PLAYLISTS_ID_MEMBERS) { 2150ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return playlistBulkInsert(db, uri, values); 2151e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } else if (match == MTP_OBJECT_REFERENCES) { 2152e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int handle = Integer.parseInt(uri.getPathSegments().get(2)); 2153e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return setObjectReferences(db, handle, values); 2154ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2155ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 2156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 2157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int numInserted = 0; 2158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = values.length; 2160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 21615d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood insertInternal(uri, match, values[i]); 2162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2163702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project numInserted = len; 2164702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 2165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 2166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 2167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2169702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return numInserted; 2170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Uri insert(Uri uri, ContentValues initialValues) 2174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2175d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood initialValues = mediaToExternalPath(initialValues); 21765d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood int match = URI_MATCHER.match(uri); 21775d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood Uri newUri = insertInternal(uri, match, initialValues); 21785d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood // do not signal notification for MTP objects. 21795d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood // we will signal instead after file transfer is successful. 2180e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood if (newUri != null && match != MTP_OBJECTS) { 2181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2182702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2183702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 2184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2185702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2186ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen private int playlistBulkInsert(SQLiteDatabase db, Uri uri, ContentValues values[]) { 2187ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen DatabaseUtils.InsertHelper helper = 2188ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen new DatabaseUtils.InsertHelper(db, "audio_playlists_map"); 21898b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int audioidcolidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID); 21908b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playlistididx = helper.getColumnIndex(Audio.Playlists.Members.PLAYLIST_ID); 21918b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorderidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.PLAY_ORDER); 21928b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 2193ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 2194ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.beginTransaction(); 2195ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int numInserted = 0; 2196ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen try { 2197ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int len = values.length; 2198ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen for (int i = 0; i < len; i++) { 21998b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.prepareForInsert(); 22008b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // getting the raw Object and converting it long ourselves saves 22018b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // an allocation (the alternative is ContentValues.getAsLong, which 22028b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // returns a Long object) 22038b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long audioid = ((Number) values[i].get( 22048b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.AUDIO_ID)).longValue(); 22058b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(audioidcolidx, audioid); 22068b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playlistididx, playlistId); 22078b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // convert to int ourselves to save an allocation. 22088b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorder = ((Number) values[i].get( 22098b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.PLAY_ORDER)).intValue(); 22108b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playorderidx, playorder); 22118b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.execute(); 2212ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2213ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen numInserted = len; 2214ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.setTransactionSuccessful(); 2215ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } finally { 2216ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.endTransaction(); 2217ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen helper.close(); 2218ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2219ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 2220ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return numInserted; 2221ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2222ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 2223b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood private long getParent(SQLiteDatabase db, String path) { 2224b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood int lastSlash = path.lastIndexOf('/'); 2225b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (lastSlash > 0) { 2226b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String parentPath = path.substring(0, lastSlash); 2227d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood if (parentPath.equals(mExternalStoragePath)) { 2228b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood return 0; 2229b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2230b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String [] selargs = { parentPath }; 223116dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood Cursor c = db.query("files", null, MediaStore.MediaColumns.DATA + "=?", 2232b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood selargs, null, null, null); 2233b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood try { 2234b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (c == null || c.getCount() == 0) { 2235b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // parent isn't in the database - so add it 2236b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood ContentValues values = new ContentValues(); 223716dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.FORMAT, MtpConstants.FORMAT_ASSOCIATION); 223816dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.DATA, parentPath); 223916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.PARENT, getParent(db, parentPath)); 224016dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood long parent = db.insert("files", FileColumns.DATE_MODIFIED, values); 2241d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood sendObjectAdded(parent); 2242d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood return parent; 2243b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 2244b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood c.moveToFirst(); 2245b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood return c.getLong(0); 2246b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2247b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } finally { 2248b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (c != null) c.close(); 2249b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2250b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 2251b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood return 0; 2252b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2253b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2254b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2255afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood private long insertFile(DatabaseHelper database, Uri uri, ContentValues initialValues, int mediaType, 2256afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood boolean notify) { 2257afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood SQLiteDatabase db = database.getWritableDatabase(); 2258afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood ContentValues values = null; 2259afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2260afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood switch (mediaType) { 2261afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FileColumns.MEDIA_TYPE_IMAGE: { 2262afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = ensureFile(database.mInternal, initialValues, ".jpg", "DCIM/Camera"); 2263afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2264afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 2265afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String data = values.getAsString(MediaColumns.DATA); 2266afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (! values.containsKey(MediaColumns.DISPLAY_NAME)) { 2267afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeDisplayName(data, values); 2268afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2269afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeTakenTime(values); 2270afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood break; 2271afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2272afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2273afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FileColumns.MEDIA_TYPE_AUDIO: { 2274afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // SQLite Views are read-only, so we need to deconstruct this 2275afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // insert and do inserts into the underlying tables. 2276afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // If doing this here turns out to be a performance bottleneck, 2277afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // consider moving this to native code and using triggers on 2278afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // the view. 2279afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = new ContentValues(initialValues); 2280afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2281afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Insert the artist into the artist table and remove it from 2282afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // the input values 2283afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Object so = values.get("artist"); 2284afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String s = (so == null ? "" : so.toString()); 2285afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove("artist"); 2286afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long artistRowId; 2287afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood HashMap<String, Long> artistCache = database.mArtistCache; 2288afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String path = values.getAsString("_data"); 2289d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood path = mediaToExternalPath(path); 2290afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood synchronized(artistCache) { 2291afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Long temp = artistCache.get(s); 2292afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (temp == null) { 2293afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood artistRowId = getKeyIdForName(db, "artists", "artist_key", "artist", 2294afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s, s, path, 0, null, artistCache, uri); 2295afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else { 2296afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood artistRowId = temp.longValue(); 2297afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2298afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2299afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String artist = s; 2300afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2301afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Do the same for the album field 2302afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood so = values.get("album"); 2303afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s = (so == null ? "" : so.toString()); 2304afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove("album"); 2305afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long albumRowId; 2306afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood HashMap<String, Long> albumCache = database.mAlbumCache; 2307afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood synchronized(albumCache) { 2308afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int albumhash = path.substring(0, path.lastIndexOf('/')).hashCode(); 2309afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String cacheName = s + albumhash; 2310afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Long temp = albumCache.get(cacheName); 2311afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (temp == null) { 2312afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood albumRowId = getKeyIdForName(db, "albums", "album_key", "album", 2313afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s, cacheName, path, albumhash, artist, albumCache, uri); 2314afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else { 2315afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood albumRowId = temp; 2316afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2317afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 23185d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood 2319afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("artist_id", Integer.toString((int)artistRowId)); 2320afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("album_id", Integer.toString((int)albumRowId)); 2321afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood so = values.getAsString("title"); 2322afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s = (so == null ? "" : so.toString()); 2323afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("title_key", MediaStore.Audio.keyFor(s)); 2324afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // do a final trim of the title, in case it started with the special 2325afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // "sort first" character (ascii \001) 2326afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove("title"); 2327afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("title", s.trim()); 2328b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2329afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeDisplayName(values.getAsString("_data"), values); 2330afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood break; 2331afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2332afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2333afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FileColumns.MEDIA_TYPE_VIDEO: { 2334afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = ensureFile(database.mInternal, initialValues, ".3gp", "video"); 2335afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String data = values.getAsString("_data"); 2336afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeDisplayName(data, values); 2337afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeTakenTime(values); 2338afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood break; 2339afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2340afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2341afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2342afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (values == null) { 2343afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = new ContentValues(initialValues); 2344afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2345fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // compute bucket_id and bucket_display_name for all files 2346afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String path = values.getAsString(MediaStore.MediaColumns.DATA); 2347fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood if (path != null) { 2348fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood computeBucketValues(path, values); 2349fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood } 2350fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 2351afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2352afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long rowId = 0; 2353afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Integer i = values.getAsInteger( 2354afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID); 2355afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (i != null) { 2356afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood rowId = i.intValue(); 2357afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = new ContentValues(values); 2358afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID); 2359afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2360afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2361afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String title = values.getAsString(MediaStore.MediaColumns.TITLE); 23623572ac7fc911cda5e4ac60af9455820a7ddf6593Marco Nelissen if (title == null && path != null) { 2363c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood title = MediaFile.getFileTitle(path); 2364c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2365c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.TITLE, title); 2366c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood 2367afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String mimeType = values.getAsString(MediaStore.MediaColumns.MIME_TYPE); 2368afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Integer formatObject = values.getAsInteger(FileColumns.FORMAT); 2369c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood int format = (formatObject == null ? 0 : formatObject.intValue()); 2370c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (format == 0) { 2371c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (path == null) { 2372c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood // special case device created playlists 2373afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType == FileColumns.MEDIA_TYPE_PLAYLIST) { 2374c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.FORMAT, MtpConstants.FORMAT_ABSTRACT_AV_PLAYLIST); 2375c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood // create a file path for the benefit of MTP 23769541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood path = mMediaStoragePath 2377afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "/Playlists/" + values.getAsString(Audio.Playlists.NAME); 2378c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(MediaStore.MediaColumns.DATA, path); 2379c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.PARENT, getParent(db, path)); 2380c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } else { 2381c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood Log.e(TAG, "path is null in insertObject()"); 2382c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2383c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } else { 2384c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood format = MediaFile.getFormatCode(path, mimeType); 2385c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2386c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2387c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (format != 0) { 2388c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.FORMAT, format); 2389c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (mimeType == null) { 2390c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood mimeType = MediaFile.getMimeTypeForFormatCode(format); 2391c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2392c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2393c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood 2394c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (mimeType == null) { 2395c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood mimeType = MediaFile.getMimeTypeForFile(path); 2396c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2397c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (mimeType != null) { 2398c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.MIME_TYPE, mimeType); 2399afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2400afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType == FileColumns.MEDIA_TYPE_NONE) { 2401afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int fileType = MediaFile.getFileTypeForMimeType(mimeType); 2402afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (MediaFile.isAudioFileType(fileType)) { 2403afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_AUDIO; 2404afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else if (MediaFile.isVideoFileType(fileType)) { 2405afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_VIDEO; 2406afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else if (MediaFile.isImageFileType(fileType)) { 2407afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_IMAGE; 2408afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else if (MediaFile.isPlayListFileType(fileType)) { 2409afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_PLAYLIST; 2410afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2411afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2412c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2413afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put(FileColumns.MEDIA_TYPE, mediaType); 2414c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood 2415afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (rowId == 0) { 2416afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType == FileColumns.MEDIA_TYPE_PLAYLIST) { 24173572ac7fc911cda5e4ac60af9455820a7ddf6593Marco Nelissen String name = values.getAsString(Audio.Playlists.NAME); 2418282dc90a0e201d992cdd0d0176028da6a565f9d5Mike Lockwood if (name == null && path == null) { 2419282dc90a0e201d992cdd0d0176028da6a565f9d5Mike Lockwood // MediaScanner will compute the name from the path if we have one 2420afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood throw new IllegalArgumentException( 2421282dc90a0e201d992cdd0d0176028da6a565f9d5Mike Lockwood "no name was provided when inserting abstract playlist"); 2422afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2423afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else { 2424afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (path == null) { 2425afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // path might be null for playlists created on the device 2426afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // or transfered via MTP 2427afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood throw new IllegalArgumentException( 2428afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "no path was provided when inserting new file"); 2429afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2430e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2431b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2432afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Long size = values.getAsLong(MediaStore.MediaColumns.SIZE); 24335d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (size == null) { 2434e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (path != null) { 2435e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood File file = new File(path); 243616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.SIZE, file.length()); 2437e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 24385d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } else { 243916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.SIZE, size); 24405d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 2441b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2442afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Long parent = values.getAsLong(FileColumns.PARENT); 24435d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (parent == null) { 2444e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (path != null) { 2445e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long parentId = getParent(db, path); 244616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.PARENT, parentId); 2447e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 24485d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } else { 244916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.PARENT, parent); 24505d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 2451b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2452afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Integer modified = values.getAsInteger(MediaStore.MediaColumns.DATE_MODIFIED); 24535d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (modified != null) { 245416dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.DATE_MODIFIED, modified); 24555d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 24565d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood 2457afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood rowId = db.insert("files", FileColumns.DATE_MODIFIED, values); 2458afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (LOCAL_LOGV) Log.v(TAG, "insertFile: values=" + values + " returned: " + rowId); 2459afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2460afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (rowId != 0 && notify) { 2461afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood sendObjectAdded(rowId); 2462afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 24635d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } else { 246416dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.update("files", values, FileColumns._ID + "=?", 2465afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood new String[] { Long.toString(rowId) }); 24665d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 2467afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2468afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood return rowId; 24691717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood } 24701717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 2471e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood private Cursor getObjectReferences(SQLiteDatabase db, int handle) { 247216dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood Cursor c = db.query("files", mMediaTableColumns, "_id=?", 2473e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Integer.toString(handle) }, 2474e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 2475e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 2476e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 2477afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long playlistId = c.getLong(0); 2478afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int mediaType = c.getInt(1); 2479afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType != FileColumns.MEDIA_TYPE_PLAYLIST) { 2480e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only support object references for playlist objects 2481e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return null; 2482e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2483e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return db.rawQuery(OBJECT_REFERENCES_QUERY, 2484afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood new String[] { Long.toString(playlistId) } ); 2485e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2486e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 2487e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 2488e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 2489e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2490e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2491e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return null; 2492e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2493e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2494e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood private int setObjectReferences(SQLiteDatabase db, int handle, ContentValues values[]) { 2495e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // first look up the media table and media ID for the object 2496e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long playlistId = 0; 249716dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood Cursor c = db.query("files", mMediaTableColumns, "_id=?", 2498e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Integer.toString(handle) }, 2499e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 2500e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 2501e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 2502afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int mediaType = c.getInt(1); 2503afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType != FileColumns.MEDIA_TYPE_PLAYLIST) { 2504e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only support object references for playlist objects 2505e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return 0; 2506e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2507afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood playlistId = c.getLong(0); 2508e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2509e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 2510e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 2511e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 2512e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2513e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2514e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (playlistId == 0) { 2515e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return 0; 2516e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2517e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2518e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // next delete any existing entries 2519e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood db.delete("audio_playlists_map", "playlist_id=?", 2520e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Long.toString(playlistId) }); 2521e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2522e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // finally add the new entries 2523e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int count = values.length; 2524e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int added = 0; 2525e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues[] valuesList = new ContentValues[count]; 2526e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood for (int i = 0; i < count; i++) { 2527e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // convert object ID to audio ID 2528e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long audioId = 0; 2529e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long objectId = values[i].getAsLong(MediaStore.MediaColumns._ID); 253016dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood c = db.query("files", mMediaTableColumns, "_id=?", 2531e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Long.toString(objectId) }, 2532e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 2533e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 2534e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 2535afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int mediaType = c.getInt(1); 253650d8650456d93e2107b9163e119c2eb9de73f804Mike Lockwood if (mediaType != FileColumns.MEDIA_TYPE_AUDIO) { 2537e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only allow audio files in playlists, so skip 2538e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood continue; 2539e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2540afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood audioId = c.getLong(0); 2541e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2542e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 2543e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 2544e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 2545e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2546e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2547e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (audioId != 0) { 2548e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues v = new ContentValues(); 2549e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood v.put(MediaStore.Audio.Playlists.Members.PLAYLIST_ID, playlistId); 2550e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood v.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audioId); 2551e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood v.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, added++); 2552e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood valuesList[i] = v; 2553e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2554e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2555e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (added < count) { 2556e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we weren't able to find everything on the list, so lets resize the array 2557e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // and pass what we have. 2558e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues[] newValues = new ContentValues[added]; 2559e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood System.arraycopy(valuesList, 0, newValues, 0, added); 2560e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood valuesList = newValues; 2561e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2562e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return playlistBulkInsert(db, 2563e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood Audio.Playlists.Members.getContentUri(EXTERNAL_VOLUME, playlistId), 2564e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood valuesList); 2565e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2566e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 25675d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood private Uri insertInternal(Uri uri, int match, ContentValues initialValues) { 2568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 2569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2570d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (LOCAL_LOGV) Log.v(TAG, "insertInternal: "+uri+", initValues="+initialValues); 2571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 2572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 2573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mMediaScannerVolume = initialValues.getAsString(MediaStore.MEDIA_SCANNER_VOLUME); 2574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return MediaStore.getMediaScannerUri(); 2575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri newUri = null; 2578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 2579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null && match != VOLUMES) { 2580702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2581702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 2582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = (match == VOLUMES ? null : database.getWritableDatabase()); 2584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 2586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: { 2587afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood rowId = insertFile(database, uri, initialValues, FileColumns.MEDIA_TYPE_IMAGE, true); 2588702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2589702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId( 2590702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Images.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 2591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2595b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This will be triggered by requestMediaThumbnail (see getThumbnailUri) 2596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: { 2597b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", 2598b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 2599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("thumbnails", "name", values); 2600702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Images.Thumbnails. 2602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContentUri(uri.getPathSegments().get(0)), rowId); 2603702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2606702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2607b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This is currently only used by MICRO_KIND video thumbnail (see getThumbnailUri) 2608b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: { 2609b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", 2610b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 2611b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen rowId = db.insert("videothumbnails", "name", values); 2612b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (rowId > 0) { 2613b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Thumbnails. 2614b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen getContentUri(uri.getPathSegments().get(0)), rowId); 2615b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2616b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 2617b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2618b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: { 2620afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood rowId = insertFile(database, uri, initialValues, FileColumns.MEDIA_TYPE_AUDIO, true); 2621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 2623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: { 2628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 2629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.AUDIO_ID, audioId); 2631ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_genres_map", "genre_id", values); 2632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: { 2639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 2640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.AUDIO_ID, audioId); 2642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_playlists_map", "playlist_id", 2643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values); 2644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2645702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2646702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2647702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2649702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2650702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: { 2651702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_genres", "audio_id", initialValues); 2652702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2653702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Genres.getContentUri(uri.getPathSegments().get(0)), rowId); 2654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: { 2659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long genreId = Long.parseLong(uri.getPathSegments().get(3)); 2660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.GENRE_ID, genreId); 2662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_genres_map", "genre_id", values); 2663702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: { 2670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.Audio.Playlists.DATE_ADDED, System.currentTimeMillis() / 1000); 2672afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood rowId = insertFile(database, uri, values, FileColumns.MEDIA_TYPE_PLAYLIST, true); 2673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Playlists.getContentUri(uri.getPathSegments().get(0)), rowId); 2675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: { 2681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 2682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.PLAYLIST_ID, playlistId); 2684ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_playlists_map", "playlist_id", values); 2685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: { 2692afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood rowId = insertFile(database, uri, initialValues, FileColumns.MEDIA_TYPE_VIDEO, true); 2693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2694b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Media.getContentUri( 2695b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen uri.getPathSegments().get(0)), rowId); 2696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2700c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood case AUDIO_ALBUMART: { 2701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database.mInternal) { 2702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("no internal album art allowed"); 2703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = null; 2705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 2707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IllegalStateException ex) { 2708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // probably no more room to store albumthumbs 2709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = initialValues; 2710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("album_art", "_data", values); 2712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2716c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VOLUMES: 2719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return attachVolume(initialValues.getAsString("name")); 2720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2721afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FILES: 2722fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood rowId = insertFile(database, uri, initialValues, 2723fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood FileColumns.MEDIA_TYPE_NONE, true); 2724fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood if (rowId > 0) { 2725fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood newUri = Files.getContentUri(uri.getPathSegments().get(0), rowId); 2726fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood } 2727fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood break; 2728fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood 2729e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS: 2730afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // don't send a notification if the insert originated from MTP 2731fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood rowId = insertFile(database, uri, initialValues, 2732fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood FileColumns.MEDIA_TYPE_NONE, false); 2733afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (rowId > 0) { 2734afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood newUri = Files.getMtpObjectsUri(uri.getPathSegments().get(0), rowId); 27355d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 27365d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood break; 27375d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood 2738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Invalid URI " + uri); 2740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2741702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2742702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 2743702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2744702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2745cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen @Override 2746cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 2747cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen throws OperationApplicationException { 2748cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 2749cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // The operations array provides no overall information about the URI(s) being operated 2750cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // on, so begin a transaction for ALL of the databases. 2751cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ihelper = getDatabaseForUri(MediaStore.Audio.Media.INTERNAL_CONTENT_URI); 2752cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ehelper = getDatabaseForUri(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI); 2753cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase idb = ihelper.getWritableDatabase(); 2754cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.beginTransaction(); 2755cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase edb = null; 2756cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (ehelper != null) { 2757cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb = ehelper.getWritableDatabase(); 2758cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.beginTransaction(); 2759cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2760cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen try { 2761cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentProviderResult[] result = super.applyBatch(operations); 2762cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.setTransactionSuccessful(); 2763cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 2764cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.setTransactionSuccessful(); 2765cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2766cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // Rather than sending targeted change notifications for every Uri 2767cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // affected by the batch operation, just invalidate the entire internal 2768cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // and external name space. 2769cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentResolver res = getContext().getContentResolver(); 2770cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen res.notifyChange(Uri.parse("content://media/"), null); 2771cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen return result; 2772cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } finally { 2773cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.endTransaction(); 2774cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 2775cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.endTransaction(); 2776cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2777cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2778cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2779cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 2780cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 27819299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen private MediaThumbRequest requestMediaThumbnail(String path, Uri uri, int priority, long magic) { 2782d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood path = mediaToExternalPath(path); 2783b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 2784e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen MediaThumbRequest req = null; 2785e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen try { 2786e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen req = new MediaThumbRequest( 27879299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen getContext().getContentResolver(), path, uri, priority, magic); 2788e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen mMediaThumbQueue.add(req); 2789e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen // Trigger the handler. 2790e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Message msg = mThumbHandler.obtainMessage(IMAGE_THUMB); 2791e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen msg.sendToTarget(); 2792e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } catch (Throwable t) { 2793e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Log.w(TAG, t); 2794e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 2795b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return req; 2796b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2797b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2798b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2799702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String generateFileName(boolean internal, String preferredExtension, String directoryName) 2800702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a random file 2802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = String.valueOf(System.currentTimeMillis()); 2803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (internal) { 2805702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Writing to internal storage is not supported."); 2806702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// return Environment.getDataDirectory() 2807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// + "/" + directoryName + "/" + name + preferredExtension; 2808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 28099541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood return mMediaStoragePath + "/" + directoryName + "/" + name + preferredExtension; 2810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private boolean ensureFileExists(String path) { 2814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(path); 2815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.exists()) { 2816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 2817702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we will not attempt to create the first directory in the path 2819702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // (for example, do not create /sdcard if the SD card is not mounted) 2820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int secondSlash = path.indexOf('/', 1); 2821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (secondSlash < 1) return false; 2822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String directoryPath = path.substring(0, secondSlash); 2823702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File directory = new File(directoryPath); 2824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!directory.exists()) 2825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 28260c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood File parent = file.getParentFile(); 28270c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood // create parent directories if necessary, and ensure they have correct permissions 28280c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood if (!parent.exists()) { 28290c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood parent.mkdirs(); 28300c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood String parentPath = parent.getPath(); 28319541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood if (parentPath.startsWith(mMediaStoragePath)) { 28329541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood while (parent != null && !mMediaStoragePath.equals(parentPath)) { 28330c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood FileUtils.setPermissions(parentPath, 0775, Process.myUid(), 28340c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood Process.SDCARD_RW_GID); 28350c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood parent = parent.getParentFile(); 28360c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood parentPath = parent.getPath(); 28370c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood } 28380c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood } 28390c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood 28400c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood } 2841702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 28420c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood if (file.createNewFile()) { 28430c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood // file should be writeable for SDCARD_RW group and world readable 28440c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood FileUtils.setPermissions(file.getPath(), 0664, Process.myUid(), 28450c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood Process.SDCARD_RW_GID); 28460c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood return true; 28470c93b04f830c0762b61fe9a7babd87128fa40e28Mike Lockwood } 2848702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch(IOException ioe) { 2849702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "File creation failed", ioe); 2850702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2851702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 2852702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2853702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2854702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2855702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final class GetTableAndWhereOutParameter { 2856702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String table; 2857702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String where; 2858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2859702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2860702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final GetTableAndWhereOutParameter sGetTableAndWhereParam = 2861702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new GetTableAndWhereOutParameter(); 2862702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2863702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void getTableAndWhere(Uri uri, int match, String userWhere, 2864702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project GetTableAndWhereOutParameter out) { 2865702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String where = null; 2866702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 28679f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin case IMAGES_MEDIA: 2868afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 2869afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_IMAGE; 28709f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin break; 28719f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin 2872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 2873afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 2874702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id = " + uri.getPathSegments().get(3); 2875702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2877b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS_ID: 2878b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 2879b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 2880b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "thumbnails"; 2881b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 2882b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2884afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 2885afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_AUDIO; 2886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2889afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 2890702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2892702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2893702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 2894702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2895702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 2896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2897702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2898702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 2899702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2900702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 2901702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND genre_id=" + uri.getPathSegments().get(5); 2902702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2903702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2904702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 2905702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2906702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 2907702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2908702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2909702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 2910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 2912702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND playlists_id=" + uri.getPathSegments().get(5); 2913702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2914702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2915702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 2916702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2917702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2918702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2919702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 2920702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2921702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2922702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2923702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2924702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 2925702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2926702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "genre_id=" + uri.getPathSegments().get(3); 2927702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2928702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2929702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 2930702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2931702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "genre_id=" + uri.getPathSegments().get(3) + 2932702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND audio_id =" + uri.getPathSegments().get(5); 2933702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2934702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2935702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 2936afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 2937afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_PLAYLIST; 2938702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2939702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2940702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2941afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 2942702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2943702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2944702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2945702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 2946702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 2947702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3); 2948702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2949702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2950702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2951702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 2952702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3) + 2953702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _id=" + uri.getPathSegments().get(5); 2954702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2955702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2956702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 2957702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "album_art"; 2958702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "album_id=" + uri.getPathSegments().get(3); 2959702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2960702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2961702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2962afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 2963afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_VIDEO; 2964702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2965702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2966702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2967afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 2968702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2969702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2970702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2971b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 2972b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 2973b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 2974b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "videothumbnails"; 2975b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 2976b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 297716dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES_ID: 2978e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS_ID: 29791717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood where = "_id=" + uri.getPathSegments().get(2); 298016dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES: 2981e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS: 298216dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood out.table = "files"; 29831717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood break; 29841717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 2985702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2986702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2987702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown or unsupported URL: " + uri.toString()); 2988702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2989702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2990702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Add in the user requested WHERE clause, if needed 2991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(userWhere)) { 2992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(where)) { 2993702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where + " AND (" + userWhere + ")"; 2994702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2995702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = userWhere; 2996702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2997702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where; 2999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3002702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 3003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int delete(Uri uri, String userWhere, String[] whereArgs) { 3004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 3005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 3006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3007702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 3008702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 3009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 3010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 0; 3011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3012702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mMediaScannerVolume = null; 3013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 1; 3014702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3015702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3016702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match != VOLUMES_ID) { 3017702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 3018702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 3019702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3020702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 3021702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3022702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 3023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 3025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 3026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 302736339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood case MTP_OBJECTS: 3028e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS_ID: 3029d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood try { 3030d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // don't send objectRemoved event since this originated from MTP 3031d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mDisableMtpObjectCallbacks = true; 303236339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood count = db.delete("files", sGetTableAndWhereParam.where, whereArgs); 3033d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } finally { 3034d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mDisableMtpObjectCallbacks = false; 3035d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 303636339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood break; 3037e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood 3038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 3039702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.delete(sGetTableAndWhereParam.table, 3040702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 3041702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3042702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 30433631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // Since there are multiple Uris that can refer to the same files 30443631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // and deletes can affect other objects in storage (like subdirectories 30453631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // or playlists) we will notify a change on the entire volume to make 30463631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // sure no listeners miss the notification. 30473631d46b679a64a16918698121916b60d7c86e97Mike Lockwood String volume = uri.getPathSegments().get(0); 30483631d46b679a64a16918698121916b60d7c86e97Mike Lockwood Uri notifyUri = Uri.parse("content://" + MediaStore.AUTHORITY + "/" + volume); 30493631d46b679a64a16918698121916b60d7c86e97Mike Lockwood getContext().getContentResolver().notifyChange(notifyUri, null); 3050702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3051702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project detachVolume(uri); 3053702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = 1; 3054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3056702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 3057702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3058702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3059702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 3060702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int update(Uri uri, ContentValues initialValues, String userWhere, 3061702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] whereArgs) { 3062d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood initialValues = mediaToExternalPath(initialValues); 3063702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 3064b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // Log.v(TAG, "update for uri="+uri+", initValues="+initialValues); 3065702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 3066702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 3067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 3068702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3069702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 3070702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3071702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 3072702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3073702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 3074702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 3075702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 30761d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // special case renaming directories via MTP. 30771d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // in this case we must update all paths in the database with 30781d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // the directory name as a prefix 30791d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if ((match == MTP_OBJECTS || match == MTP_OBJECTS_ID) 30801d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood && initialValues != null && initialValues.size() == 1) { 30811d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood String oldPath = null; 30821d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood String newPath = initialValues.getAsString("_data"); 30831d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // MtpDatabase will rename the directory first, so we test the new file name 30841d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (newPath != null && (new File(newPath)).isDirectory()) { 30851d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood Cursor cursor = db.query(sGetTableAndWhereParam.table, PATH_PROJECTION, 30861d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood userWhere, whereArgs, null, null, null); 30871d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood try { 30881d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (cursor != null && cursor.moveToNext()) { 30891d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood oldPath = cursor.getString(1); 30901d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 30911d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } finally { 30921d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (cursor != null) cursor.close(); 30931d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 30941d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (oldPath != null) { 30951d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // first rename the row for the directory 30961d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood count = db.update(sGetTableAndWhereParam.table, initialValues, 30971d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood sGetTableAndWhereParam.where, whereArgs); 30981d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (count > 0) { 30991d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // then update the paths of any files and folders contained in the directory. 31001d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood db.execSQL("UPDATE files SET _data=REPLACE(_data, '" 31011d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood + oldPath + "/','" + newPath + "/');"); 31021d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 31031d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood 31041d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (count > 0 && !db.inTransaction()) { 31051d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood getContext().getContentResolver().notifyChange(uri, null); 31061d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 31071d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood return count; 31081d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 31091d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 31101d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 31111d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood 3112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 3113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 3114702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 3115702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 3116702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 311707656cccafca173c6ab54c681a69538dcf0516ddMarco Nelissen 3118702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Insert the artist into the artist table and remove it from 3119702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the input values 3120a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist = values.getAsString("artist"); 31216006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("artist"); 3122a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (artist != null) { 3123702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long artistRowId; 3124702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> artistCache = database.mArtistCache; 3125702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(artistCache) { 3126a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen Long temp = artistCache.get(artist); 3127702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 3128acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen artistRowId = getKeyIdForName(db, "artists", "artist_key", "artist", 3129acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen artist, artist, null, 0, null, artistCache, uri); 3130702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3131702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = temp.longValue(); 3132702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3133702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3134702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("artist_id", Integer.toString((int)artistRowId)); 3135702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3136702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 313759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Do the same for the album field. 3138a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String so = values.getAsString("album"); 31396006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("album"); 3140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 314159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String path = values.getAsString("_data"); 314259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen int albumHash = 0; 314359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (path == null) { 314459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // If the path is null, we don't have a hash for the file in question. 314559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Log.w(TAG, "Update without specified path."); 314659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } else { 3147d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood path = mediaToExternalPath(path); 314859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen albumHash = path.substring(0, path.lastIndexOf('/')).hashCode(); 314959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 3150702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 3151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long albumRowId; 3152702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> albumCache = database.mAlbumCache; 3153702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(albumCache) { 315459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String cacheName = s + albumHash; 315559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Long temp = albumCache.get(cacheName); 3156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 3157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = getKeyIdForName(db, "albums", "album_key", "album", 3158a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, cacheName, path, albumHash, artist, albumCache, uri); 3159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = temp.longValue(); 3161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3163702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("album_id", Integer.toString((int)albumRowId)); 3164702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // don't allow the title_key field to be updated directly 3167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("title_key"); 3168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the title field is modified, update the title_key 3169702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.getAsString("title"); 3170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 3171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 3172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("title_key", MediaStore.Audio.keyFor(s)); 3173e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // do a final trim of the title, in case it started with the special 3174e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // "sort first" character (ascii \001) 3175e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.remove("title"); 3176e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.put("title", s.trim()); 3177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3179afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood count = db.update(sGetTableAndWhereParam.table, values, 3180afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood sGetTableAndWhereParam.where, whereArgs); 3181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3182702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3183702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 3184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 3185702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 3186702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 3187702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 3188702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 3189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Don't allow bucket id or display name to be updated directly. 3190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // The same names are used for both images and table columns, so 3191702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we use the ImageColumns constants here. 3192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_ID); 3193702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_DISPLAY_NAME); 3194702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the data is being modified update the bucket values 3195702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString(MediaColumns.DATA); 3196702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (data != null) { 3197702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 3198702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3199b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen computeTakenTime(values); 3200702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, values, 3201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 320201a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // if this is a request from MediaScanner, DATA should contains file path 320301a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // we only process update request from media scanner, otherwise the requests 320401a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // could be duplicate. 320501a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen if (count > 0 && values.getAsString(MediaStore.MediaColumns.DATA) != null) { 320601a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen Cursor c = db.query(sGetTableAndWhereParam.table, 320701a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen READY_FLAG_PROJECTION, sGetTableAndWhereParam.where, 320801a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen whereArgs, null, null, null); 3209b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c != null) { 3210216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen try { 3211216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen while (c.moveToNext()) { 3212216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen long magic = c.getLong(2); 3213216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (magic == 0) { 3214216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen requestMediaThumbnail(c.getString(1), uri, 3215216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen MediaThumbRequest.PRIORITY_NORMAL, 0); 3216216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 3217b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3218216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } finally { 3219216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c.close(); 3220b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3221b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3222b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3223702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3225f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 3226f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 3227f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String moveit = uri.getQueryParameter("move"); 3228f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (moveit != null) { 3229f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String key = MediaStore.Audio.Playlists.Members.PLAY_ORDER; 3230f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (initialValues.containsKey(key)) { 3231f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int newpos = initialValues.getAsInteger(key); 3232f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen List <String> segments = uri.getPathSegments(); 3233f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen long playlist = Long.valueOf(segments.get(3)); 3234f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int oldpos = Integer.valueOf(segments.get(5)); 3235f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return movePlaylistEntry(db, playlist, oldpos, newpos); 3236f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3237f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen throw new IllegalArgumentException("Need to specify " + key + 3238f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " when using 'move' parameter"); 3239f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3240f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // fall through 3241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 3242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, initialValues, 3243702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 3244702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3245702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3246702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3247cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // in a transaction, the code that began the transaction should be taking 3248cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // care of notifications once it ends the transaction successfully 3249cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (count > 0 && !db.inTransaction()) { 3250702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 3251702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3252702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 3253702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3254702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3255f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen private int movePlaylistEntry(SQLiteDatabase db, long playlist, int from, int to) { 3256f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from == to) { 3257f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return 0; 3258f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3259f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.beginTransaction(); 3260f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen try { 3261f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int numlines = 0; 3262f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=-1" + 3263f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order=" + from + 3264f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 3265f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // We could just run both of the next two statements, but only one of 3266f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // of them will actually do anything, so might as well skip the compile 3267f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // and execute steps. 3268f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from < to) { 3269f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order-1" + 3270f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order<=" + to + " AND play_order>" + from + 3271f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 3272f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = to - from + 1; 3273f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } else { 3274f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order+1" + 3275f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order>=" + to + " AND play_order<" + from + 3276f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 3277f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = from - to + 1; 3278f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3279f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=" + to + 3280f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order=-1 AND playlist_id=" + playlist); 3281f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.setTransactionSuccessful(); 3282f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen Uri uri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI 3283f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen .buildUpon().appendEncodedPath(String.valueOf(playlist)).build(); 3284f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 3285f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return numlines; 3286f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } finally { 3287f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.endTransaction(); 3288f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3289f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3290f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 3291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] openFileColumns = new String[] { 3292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.DATA, 3293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 3294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3295d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood /* Same as ContentProvider.openFileHelper, except we will convert paths 3296d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood in external storage to internal media storage to avoid Fuse overhead. 3297d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood */ 3298d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood private final ParcelFileDescriptor doOpenFile(Uri uri, 3299d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood String mode) throws FileNotFoundException { 3300d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood Cursor c = query(uri, new String[]{"_data"}, null, null, null); 3301d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood int count = (c != null) ? c.getCount() : 0; 3302d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood if (count != 1) { 3303d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood // If there is not exactly one result, throw an appropriate 3304d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood // exception. 3305d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood if (c != null) { 3306d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood c.close(); 3307d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood } 3308d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood if (count == 0) { 3309d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood throw new FileNotFoundException("No entry for " + uri); 3310d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood } 3311d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood throw new FileNotFoundException("Multiple items at " + uri); 3312d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood } 3313d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood 3314d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood c.moveToFirst(); 3315d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood int i = c.getColumnIndex("_data"); 3316d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood String path = (i >= 0 ? c.getString(i) : null); 3317d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood c.close(); 3318d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood if (path == null) { 3319d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood throw new FileNotFoundException("Column _data not found."); 3320d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood } 3321d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood 3322d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood path = externalToMediaPath(path); 3323d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood int modeBits = ContentResolver.modeToMode(uri, mode); 3324d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood return ParcelFileDescriptor.open(new File(path), modeBits); 3325d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood } 3326d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood 3327702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 3328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public ParcelFileDescriptor openFile(Uri uri, String mode) 3329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throws FileNotFoundException { 333071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 3331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = null; 333271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 333371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_FILE_ID) { 333471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // get album art for the specified media file 333571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen DatabaseHelper database = getDatabaseForUri(uri); 333671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (database == null) { 333771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw new IllegalStateException("Couldn't open database for " + uri); 333871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 333971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteDatabase db = database.getReadableDatabase(); 334071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 334171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int songid = Integer.parseInt(uri.getPathSegments().get(3)); 334271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 334371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.appendWhere("_id=" + songid); 334471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Cursor c = qb.query(db, 334571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen new String [] { 334671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.DATA, 334771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.ALBUM_ID }, 334871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen null, null, null, null, null); 334971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 335071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen String audiopath = c.getString(0); 335171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int albumid = c.getInt(1); 335271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // Try to get existing album art for this album first, which 335371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // could possibly have been obtained from a different file. 335471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // If that fails, try to get it from this specific file. 335571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri newUri = ContentUris.withAppendedId(ALBUMART_URI, albumid); 335671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 335771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = openFile(newUri, mode); // recursive call 335871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (FileNotFoundException ex) { 335971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // That didn't work, now try to get it from the specific file 336071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, null); 336171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 336271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 336371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen c.close(); 336471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return pfd; 336571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 336671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 3367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd = openFileHelper(uri, mode); 3369702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (FileNotFoundException ex) { 337071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (mode.contains("w")) { 337171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // if the file couldn't be created, we shouldn't extract album art 337271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 337371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 337471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 3375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_ID) { 3376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Tried to open an album art file which does not exist. Regenerate. 3377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 3378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 3379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw ex; 3380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3381702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getReadableDatabase(); 3382702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 3383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int albumid = Integer.parseInt(uri.getPathSegments().get(3)); 338471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 3385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("album_id=" + albumid); 3386702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, 3387702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String [] { 3388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Media.DATA }, 3389a4d7f8a140c9a66bfcb28c5197521db6d62e13beMarco Nelissen null, null, null, null, MediaStore.Audio.Media.TRACK); 339071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 3391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String audiopath = c.getString(0); 339271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, uri); 3393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.close(); 3395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 339671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (pfd == null) { 339771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 339871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 3399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return pfd; 3401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private class ThumbData { 3404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db; 3405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path; 3406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long album_id; 3407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri albumart_uri; 3408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3410a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen private void makeThumbAsync(SQLiteDatabase db, String path, long album_id) { 34118a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mPendingThumbs) { 34128a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (mPendingThumbs.contains(path)) { 34138a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // There's already a request to make an album art thumbnail 34148a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // for this audio file in the queue. 34158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return; 34168a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 34178a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 34188a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mPendingThumbs.add(path); 34198a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 34208a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 3421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ThumbData d = new ThumbData(); 3422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.db = db; 3423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.path = path; 3424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.album_id = album_id; 3425a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen d.albumart_uri = ContentUris.withAppendedId(mAlbumArtBaseUri, album_id); 34268a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 34278a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Instead of processing thumbnail requests in the order they were 34288a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // received we instead process them stack-based, i.e. LIFO. 34298a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The idea behind this is that the most recently requested thumbnails 34308a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // are most likely the ones still in the user's view, whereas those 34318a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // requested earlier may have already scrolled off. 34328a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mThumbRequestStack) { 34338a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mThumbRequestStack.push(d); 34348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 34358a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 34368a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Trigger the handler. 3437b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Message msg = mThumbHandler.obtainMessage(ALBUM_THUMB); 3438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project msg.sendToTarget(); 3439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 34418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Extract compressed image data from the audio file itself or, if that fails, 34428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // look for a file "AlbumArt.jpg" in the containing directory. 34438a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private static byte[] getCompressedAlbumArt(Context context, String path) { 34448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = null; 3445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3447d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood path = mediaToExternalPath(path); 3448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File f = new File(path); 3449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, 3450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor.MODE_READ_ONLY); 3451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 34528a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber MediaScanner scanner = new MediaScanner(context); 34538a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber compressed = scanner.extractAlbumArt(pfd.getFileDescriptor()); 3454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd.close(); 3455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3456d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // If no embedded art exists, look for a suitable image file in the 34573f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // same directory as the media file, except if that directory is 34583f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // is the root directory of the sd card or the download directory. 3459d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // We look for, in order of preference: 3460d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 0 AlbumArt.jpg 3461d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 1 AlbumArt*Large.jpg 3462d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 2 Any other jpg image with 'albumart' anywhere in the name 3463d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 3 Any other jpg image 3464d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 4 any other png image 34658a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null && path != null) { 3466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lastSlash = path.lastIndexOf('/'); 3467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lastSlash > 0) { 3468d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 34693f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen String artPath = path.substring(0, lastSlash); 34709541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood String sdroot = mMediaStoragePath; 34710fe3097230b324e65a874bd7c8c0f430d2fb8cbeMarco Nelissen String dwndir = Environment.getExternalStoragePublicDirectory( 34722f07f572bc574b685b491ee07a6209c7f2dcb13fMarco Nelissen Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(); 3473d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 3474d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String bestmatch = null; 3475d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen synchronized (sFolderArtMap) { 3476d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (sFolderArtMap.containsKey(artPath)) { 3477d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = sFolderArtMap.get(artPath); 3478ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } else if (!artPath.equalsIgnoreCase(sdroot) && 3479ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen !artPath.equalsIgnoreCase(dwndir)) { 3480d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen File dir = new File(artPath); 3481d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String [] entrynames = dir.list(); 3482d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entrynames == null) { 3483d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen return null; 3484d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 3485d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = null; 3486d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen int matchlevel = 1000; 3487d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen for (int i = entrynames.length - 1; i >=0; i--) { 3488d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String entry = entrynames[i].toLowerCase(); 3489d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entry.equals("albumart.jpg")) { 3490d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3491d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen break; 3492d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.startsWith("albumart") 3493d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith("large.jpg") 3494d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 1) { 3495d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3496d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 1; 3497d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.contains("albumart") 3498d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith(".jpg") 3499d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 2) { 3500d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3501d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 2; 3502d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".jpg") && matchlevel > 3) { 3503d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3504d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 3; 3505d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".png") && matchlevel > 4) { 3506d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3507d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 4; 3508d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 3509d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 3510d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // note that this may insert null if no album art was found 3511d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen sFolderArtMap.put(artPath, bestmatch); 3512d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 3513d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 3514d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 3515d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (bestmatch != null) { 35163f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen File file = new File(artPath, bestmatch); 3517d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (file.exists()) { 3518d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = new byte[(int)file.length()]; 3519d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen FileInputStream stream = null; 3520d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen try { 3521d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream = new FileInputStream(file); 3522d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.read(compressed); 3523d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } catch (IOException ex) { 3524d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = null; 3525d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } finally { 3526d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (stream != null) { 3527d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.close(); 3528d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 3529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 35348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IOException e) { 35358a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 3536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 35378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return compressed; 35388a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 3539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 35408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Return a URI to write the album art to and update the database as necessary. 35418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Uri getAlbumArtOutputUri(SQLiteDatabase db, long album_id, Uri albumart_uri) { 35428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Uri out = null; 35438a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // TODO: this could be done more efficiently with a call to db.replace(), which 35448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // replaces or inserts as needed, making it unnecessary to query() first. 35458a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (albumart_uri != null) { 35468a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Cursor c = query(albumart_uri, new String [] { "_data" }, 35478a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber null, null, null); 3548d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson try { 3549d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson if (c != null && c.moveToFirst()) { 3550d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson String albumart_path = c.getString(0); 3551d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson if (ensureFileExists(albumart_path)) { 3552d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson out = albumart_uri; 3553d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } 3554d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } else { 3555d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson albumart_uri = null; 3556d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } 3557d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } finally { 3558d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson if (c != null) { 3559d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson c.close(); 3560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 356271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 356371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (albumart_uri == null){ 35648a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues initialValues = new ContentValues(); 35658a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber initialValues.put("album_id", album_id); 35668a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 35678a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 35688a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber long rowId = db.insert("album_art", "_data", values); 35698a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (rowId > 0) { 35708a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber out = ContentUris.withAppendedId(ALBUMART_URI, rowId); 3571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 35728a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IllegalStateException ex) { 35738a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating album thumb file"); 35748a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 35758a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 35768a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return out; 35778a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 35788a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 35798a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Write out the album art to the output URI, recompresses the given Bitmap 35808a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // if necessary, otherwise writes the compressed data. 35818a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private void writeAlbumArt( 35828a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress, Uri out, byte[] compressed, Bitmap bm) { 35838a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean success = false; 35848a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 35858a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber OutputStream outstream = getContext().getContentResolver().openOutputStream(out); 35868a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 35878a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!need_to_recompress) { 35888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // No need to recompress here, just write out the original 35898a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // compressed data here. 35908a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.write(compressed); 35918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber success = true; 35928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 35938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber success = bm.compress(Bitmap.CompressFormat.JPEG, 75, outstream); 3594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 35958a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 35968a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.close(); 35978a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (FileNotFoundException ex) { 35988a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 3599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IOException ex) { 36008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 36018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 36028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!success) { 36038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // the thumbnail was not written successfully, delete the entry that refers to it 36048a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber getContext().getContentResolver().delete(out, null, null); 3605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 36068a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 36078a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 360871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor getThumb(SQLiteDatabase db, String path, long album_id, 360971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri albumart_uri) { 361071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen ThumbData d = new ThumbData(); 361171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.db = db; 361271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.path = path; 361371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.album_id = album_id; 361471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.albumart_uri = albumart_uri; 361571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return makeThumbInternal(d); 361671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 361771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 361871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor makeThumbInternal(ThumbData d) { 36198a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = getCompressedAlbumArt(getContext(), d.path); 3620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 36218a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null) { 362271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 36238a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 36248a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 36258a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Bitmap bm = null; 36268a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress = true; 36278a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 36288a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 36298a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the size of the bitmap 36308a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.Options opts = new BitmapFactory.Options(); 36318a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = true; 36328a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize = 1; 36338a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 36348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 36358a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // request a reasonably sized output image 36368a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // TODO: don't hardcode the size 36378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber while (opts.outHeight > 320 || opts.outWidth > 320) { 36388a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outHeight /= 2; 36398a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outWidth /= 2; 36408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize *= 2; 36418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 36428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 36438a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (opts.inSampleSize == 1) { 36448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The original album art was of proper size, we won't have to 36458a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // recompress the bitmap later. 36468a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber need_to_recompress = false; 36478a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 36488a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the image for real now 36498a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = false; 36508a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inPreferredConfig = Bitmap.Config.RGB_565; 36518a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber bm = BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 36528a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 36538a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (bm != null && bm.getConfig() == null) { 3654a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen Bitmap nbm = bm.copy(Bitmap.Config.RGB_565, false); 3655a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (nbm != null && nbm != bm) { 3656a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 3657a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm = nbm; 3658a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 36598a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 36608a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 36618a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (Exception e) { 36628a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 36638a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 36648a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (need_to_recompress && bm == null) { 366571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 36668a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 36678a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 366871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (d.albumart_uri == null) { 366971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // this one doesn't need to be saved (probably a song with an unknown album), 367071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // so stick it in a memory file and return that 367171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 367224001394f571b1f0378840cbf299288e4df10508Bjorn Bringert return ParcelFileDescriptor.fromData(compressed, "albumthumb"); 367371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (IOException e) { 367471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 367571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } else { 3676a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This one needs to actually be saved on the sd card. 3677a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This is wrapped in a transaction because there are various things 3678a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // that could go wrong while generating the thumbnail, and we only want 3679a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // to update the database when all steps succeeded. 3680a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.beginTransaction(); 3681a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen try { 3682a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen Uri out = getAlbumArtOutputUri(d.db, d.album_id, d.albumart_uri); 3683a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen 3684a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (out != null) { 3685a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen writeAlbumArt(need_to_recompress, out, compressed, bm); 3686a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen getContext().getContentResolver().notifyChange(MEDIA_URI, null); 3687a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen ParcelFileDescriptor pfd = openFileHelper(out, "r"); 3688a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.setTransactionSuccessful(); 3689a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen return pfd; 3690a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 3691a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (FileNotFoundException ex) { 3692a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 3693a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (UnsupportedOperationException ex) { 3694a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 3695a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } finally { 3696a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.endTransaction(); 3697a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (bm != null) { 3698a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 369971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 370071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 37018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 370271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 3703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Look up the artist or album entry for the given name, creating that entry 3707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * if it does not already exists. 3708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db The database 3709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param table The table to store the key/name pair in. 3710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param keyField The name of the key-column 3711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param nameField The name of the name-column 3712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param rawName The name that the calling app was trying to insert into the database 371359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param cacheName The string that will be inserted in to the cache 371459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param path The full path to the file being inserted in to the audio table 371559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param albumHash A hash to distinguish between different albums of the same name 3716a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen * @param artist The name of the artist, if known 3717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param cache The cache to add this entry to 3718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param srcuri The Uri that prompted the call to this method, used for determining whether this is 3719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * the internal or external database 3720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The row ID for this artist/album, or -1 if the provided name was invalid 3721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3722702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private long getKeyIdForName(SQLiteDatabase db, String table, String keyField, String nameField, 372359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String rawName, String cacheName, String path, int albumHash, 3724a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist, HashMap<String, Long> cache, Uri srcuri) { 3725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 3726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rawName == null || rawName.length() == 0) { 3728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return -1; 3729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String k = MediaStore.Audio.keyFor(rawName); 3731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (k == null) { 3733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return -1; 3734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 373659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen boolean isAlbum = table.equals("albums"); 3737e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen boolean isUnknown = MediaStore.UNKNOWN_STRING.equals(rawName); 373859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 373959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // To distinguish same-named albums, we append a hash of the path. 374059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Ideally we would also take things like CDDB ID in to account, so 374159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // we can group files from the same album that aren't in the same 374259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // folder, but this is a quick and easy start that works immediately 374359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // without requiring support from the mp3, mp4 and Ogg meta data 374459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // readers, as long as the albums are in different folders. 3745a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isAlbum) { 374659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen k = k + albumHash; 3747a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isUnknown) { 3748a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen k = k + artist; 3749a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen } 375059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 375159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 3752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] selargs = { k }; 3753702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = db.query(table, null, keyField + "=?", selargs, null, null, null); 3754702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3755702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (c.getCount()) { 3757702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 0: { 3758702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // insert new entry into table 3759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues otherValues = new ContentValues(); 3760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(keyField, k); 3761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(nameField, rawName); 3762702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert(table, "duration", otherValues); 376359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (path != null && isAlbum && ! isUnknown) { 3764702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We just inserted a new album. Now create an album art thumbnail for it. 3765a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen makeThumbAsync(db, path, rowId); 3766702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3767702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3768702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 3769702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 3770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 3771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3772702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3773702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3774702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 1: { 3775702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Use the existing entry 3776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.moveToFirst(); 3777702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = c.getLong(0); 3778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3779702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Determine whether the current rawName is better than what's 3780702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // currently stored in the table, and update the table if it is. 3781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String currentFancyName = c.getString(2); 3782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String bestName = makeBestName(rawName, currentFancyName); 3783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!bestName.equals(currentFancyName)) { 3784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // update the table with the new name 3785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues newValues = new ContentValues(); 3786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newValues.put(nameField, bestName); 3787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(table, newValues, "rowid="+Integer.toString((int)rowId), null); 3788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 3789702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 3790702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 3791702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3792702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3793702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3794702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 3795702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // corrupt database 3796702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Multiple entries in table " + table + " for key " + k); 3797702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = -1; 3798702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3799702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3800702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 3801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) c.close(); 3802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 380459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (cache != null && ! isUnknown) { 380559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen cache.put(cacheName, rowId); 3806702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return rowId; 3808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3809702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Returns the best string to use for display, given two names. 3812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Note that this function does not necessarily return either one 3813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * of the provided names; it may decide to return a better alternative 3814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * (for example, specifying the inputs "Police" and "Police, The" will 3815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * return "The Police") 3816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3817702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * The basic assumptions are: 3818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - longer is better ("The police" is better than "Police") 3819702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - prefix is better ("The Police" is better than "Police, The") 3820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - accents are better ("Motörhead" is better than "Motorhead") 3821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param one The first of the two names to consider 3823702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param two The last of the two names to consider 3824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The actual name to use 3825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3826702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String makeBestName(String one, String two) { 3827702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name; 3828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3829702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Longer names are usually better. 3830702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.length() > two.length()) { 3831702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 3832702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3833702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Names with accents are usually better, and conveniently sort later 3834702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.toLowerCase().compareTo(two.toLowerCase()) > 0) { 3835702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 3836702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3837702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = two; 3838702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3839702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3840702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3841702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Prefixes are better than postfixes. 3842702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (name.endsWith(", the") || name.endsWith(",the") || 3843702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", an") || name.endsWith(",an") || 3844702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", a") || name.endsWith(",a")) { 3845702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String fix = name.substring(1 + name.lastIndexOf(',')); 3846702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = fix.trim() + " " + name.substring(0, name.lastIndexOf(',')); 3847702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3848702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3849702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // TODO: word-capitalize the resulting name 3850702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return name; 3851702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3852702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3853702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3854702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3855702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Looks up the database based on the given URI. 3856702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3857702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The requested URI 3858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @returns the database for the given URI 3859702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3860702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private DatabaseHelper getDatabaseForUri(Uri uri) { 3861702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 3862702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getPathSegments().size() > 1) { 3863702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return mDatabases.get(uri.getPathSegments().get(0)); 3864702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3865702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3866702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 3867702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3868702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3869702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Attach the database for a volume (internal or external). 3871702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already attached, otherwise 3872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * checks the volume ID and sets up the corresponding database. 3873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3874702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param volume to attach, either {@link #INTERNAL_VOLUME} or {@link #EXTERNAL_VOLUME}. 3875702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the content URI of the attached volume. 3876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3877702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Uri attachVolume(String volume) { 3878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Process.supportsProcesses() && Binder.getCallingPid() != Process.myPid()) { 3879702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 3880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 3881702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3882702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 3884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mDatabases.get(volume) != null) { // Already attached 3885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 3886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper db; 3889702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 3890702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db = new DatabaseHelper(getContext(), INTERNAL_DATABASE_NAME, true); 3891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (EXTERNAL_VOLUME.equals(volume)) { 38929541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood String path = mMediaStoragePath; 3893702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int volumeID = FileUtils.getFatVolumeId(path); 3894702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, path + " volume ID: " + volumeID); 3895702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // generate database name based on volume ID 3897702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String dbName = "external-" + Integer.toHexString(volumeID) + ".db"; 3898702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db = new DatabaseHelper(getContext(), dbName, false); 38990027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen mVolumeId = volumeID; 3900702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3901702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException("There is no volume named " + volume); 3902702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3903702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3904702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases.put(volume, db); 3905702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3906702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!db.mInternal) { 3907702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // clean up stray album art files: delete every file not in the database 39089541d036d207aba5f940ae8093aed20c9c229e1bMike Lockwood File[] files = new File(mMediaStoragePath, ALBUM_THUMB_FOLDER).listFiles(); 3909702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashSet<String> fileSet = new HashSet(); 3910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; files != null && i < files.length; i++) { 3911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.add(files[i].getPath()); 3912702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3913702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3914702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, 3915702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String[] { MediaStore.Audio.Albums.ALBUM_ART }, null, null, null); 3916702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3917702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor != null && cursor.moveToNext()) { 3918702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.remove(cursor.getString(0)); 3919702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3920702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 3921702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (cursor != null) cursor.close(); 3922702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3923702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3924702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Iterator<String> iterator = fileSet.iterator(); 3925702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (iterator.hasNext()) { 3926702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String filename = iterator.next(); 3927702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "deleting obsolete album art " + filename); 3928702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new File(filename).delete(); 3929702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3930702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3931702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3932702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3933702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Attached volume: " + volume); 3934702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 3935702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3936702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3937702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3938702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Detach the database for a volume (must be external). 3939702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already detached, otherwise 3940702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * closes the database and sends a notification to listeners. 3941702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3942702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The content URI of the volume, as returned by {@link #attachVolume} 3943702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3944702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void detachVolume(Uri uri) { 3945702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Process.supportsProcesses() && Binder.getCallingPid() != Process.myPid()) { 3946702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 3947702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 3948702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3949702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3950702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = uri.getPathSegments().get(0); 3951702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 3952702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3953702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Deleting the internal volume is not allowed"); 3954702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (!EXTERNAL_VOLUME.equals(volume)) { 3955702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException( 3956702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "There is no volume named " + volume); 3957702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3958702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3959702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 3960702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = mDatabases.get(volume); 3961702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) return; 3962702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3963702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3964702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 3965702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(database.getReadableDatabase().getPath()); 3966702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(System.currentTimeMillis()); 3967702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (SQLException e) { 3968702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Can't touch database file", e); 3969702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3970702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3971702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases.remove(volume); 3972702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project database.close(); 3973702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3974702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3975702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 3976702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Detached volume: " + volume); 3977702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3978702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3979702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static String TAG = "MediaProvider"; 3980ae62a1d602e7ed2e0e30e271bddbb27aa71469f6Christian Mehlmauer private static final boolean LOCAL_LOGV = false; 3981fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood private static final int DATABASE_VERSION = 300; 3982702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String INTERNAL_DATABASE_NAME = "internal.db"; 3983702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3984702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // maximum number of cached external databases to keep 3985702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MAX_EXTERNAL_DATABASES = 3; 3986702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3987702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Delete databases that have not been used in two months 3988702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // 60 days in milliseconds (1000 * 60 * 60 * 24 * 60) 3989702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final long OBSOLETE_DATABASE_DB = 5184000000L; 3990702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private HashMap<String, DatabaseHelper> mDatabases; 3992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3993702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Handler mThumbHandler; 3994702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3995702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // name of the volume currently being scanned by the media scanner (or null) 3996702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mMediaScannerVolume; 3997702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 39980027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // current FAT volume ID 39990027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen private int mVolumeId; 40000027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 4001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String INTERNAL_VOLUME = "internal"; 4002702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String EXTERNAL_VOLUME = "external"; 4003268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen static final String ALBUM_THUMB_FOLDER = "Android/data/com.android.providers.media/albumthumbs"; 4004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // path for writing contents of in memory temp database 4006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mTempDatabasePath; 4007702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 40081717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // WARNING: the values of IMAGES_MEDIA, AUDIO_MEDIA, and VIDEO_MEDIA and AUDIO_PLAYLISTS 400916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood // are stored in the "files" table, so do not renumber them unless you also add 40101717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // a corresponding database upgrade step for it. 4011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA = 1; 4012702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA_ID = 2; 4013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS = 3; 4014702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS_ID = 4; 4015702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4016702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA = 100; 4017702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID = 101; 4018702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES = 102; 4019702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES_ID = 103; 4020702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS = 104; 4021702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS_ID = 105; 4022702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES = 106; 4023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID = 107; 4024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID_MEMBERS = 108; 4025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID_MEMBERS_ID = 109; 4026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS = 110; 4027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID = 111; 4028702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS = 112; 4029702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS_ID = 113; 4030702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS = 114; 4031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID = 115; 4032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS = 116; 4033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS_ID = 117; 4034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID_ALBUMS = 118; 4035702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART = 119; 4036702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART_ID = 120; 403771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private static final int AUDIO_ALBUMART_FILE_ID = 121; 4038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4039702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA = 200; 4040702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA_ID = 201; 4041b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS = 202; 4042b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS_ID = 203; 4043702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4044702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES = 300; 4045702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES_ID = 301; 4046702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4047a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_LEGACY = 400; 4048a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_BASIC = 401; 4049a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_FANCY = 402; 4050702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4051702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MEDIA_SCANNER = 500; 4052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 40530027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen private static final int FS_ID = 600; 40540027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 405516dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood private static final int FILES = 700; 405616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood private static final int FILES_ID = 701; 4057e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood 4058e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood // Used only by the MTP implementation 4059e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood private static final int MTP_OBJECTS = 702; 4060e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood private static final int MTP_OBJECTS_ID = 703; 4061e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood private static final int MTP_OBJECT_REFERENCES = 704; 4062b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 4063702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final UriMatcher URI_MATCHER = 4064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new UriMatcher(UriMatcher.NO_MATCH); 4065702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4066b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] ID_PROJECTION = new String[] { 4067b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID 4068b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 4069b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 40701d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood private static final String[] PATH_PROJECTION = new String[] { 40711d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood MediaStore.MediaColumns._ID, 40721d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood MediaStore.MediaColumns.DATA, 40731d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood }; 40741d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood 4075702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] MIME_TYPE_PROJECTION = new String[] { 4076702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns._ID, // 0 4077702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.MIME_TYPE, // 1 4078702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 4079702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4080b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] READY_FLAG_PROJECTION = new String[] { 4081b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID, 4082b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns.DATA, 4083b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Images.Media.MINI_THUMB_MAGIC 4084b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 4085b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 4086e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood private static final String OBJECT_REFERENCES_QUERY = 4087afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT " + Audio.Playlists.Members.AUDIO_ID + " FROM audio_playlists_map" 4088afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + " WHERE " + Audio.Playlists.Members.PLAYLIST_ID + "=?" 4089afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + " ORDER BY " + Audio.Playlists.Members.PLAY_ORDER; 4090e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 4091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static 4092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 4093702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media", IMAGES_MEDIA); 4094702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media/#", IMAGES_MEDIA_ID); 4095702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails", IMAGES_THUMBNAILS); 4096702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails/#", IMAGES_THUMBNAILS_ID); 4097702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4098702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media", AUDIO_MEDIA); 4099702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#", AUDIO_MEDIA_ID); 4100702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES); 4101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres/#", AUDIO_MEDIA_ID_GENRES_ID); 4102702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists", AUDIO_MEDIA_ID_PLAYLISTS); 4103702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists/#", AUDIO_MEDIA_ID_PLAYLISTS_ID); 4104702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres", AUDIO_GENRES); 4105702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#", AUDIO_GENRES_ID); 4106702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#/members", AUDIO_GENRES_ID_MEMBERS); 4107702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#/members/#", AUDIO_GENRES_ID_MEMBERS_ID); 4108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists", AUDIO_PLAYLISTS); 4109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#", AUDIO_PLAYLISTS_ID); 4110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members", AUDIO_PLAYLISTS_ID_MEMBERS); 4111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members/#", AUDIO_PLAYLISTS_ID_MEMBERS_ID); 4112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists", AUDIO_ARTISTS); 4113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#", AUDIO_ARTISTS_ID); 4114702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#/albums", AUDIO_ARTISTS_ID_ALBUMS); 4115702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums", AUDIO_ALBUMS); 4116702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums/#", AUDIO_ALBUMS_ID); 4117702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart", AUDIO_ALBUMART); 4118702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart/#", AUDIO_ALBUMART_ID); 411971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen URI_MATCHER.addURI("media", "*/audio/media/#/albumart", AUDIO_ALBUMART_FILE_ID); 4120702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4121702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media", VIDEO_MEDIA); 4122702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media/#", VIDEO_MEDIA_ID); 4123b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails", VIDEO_THUMBNAILS); 4124b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails/#", VIDEO_THUMBNAILS_ID); 4125702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4126702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/media_scanner", MEDIA_SCANNER); 4127702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 41280027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen URI_MATCHER.addURI("media", "*/fs_id", FS_ID); 41290027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 4130702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*", VOLUMES_ID); 4131702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", null, VOLUMES); 4132702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4133b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // Used by MTP implementation 413416dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood URI_MATCHER.addURI("media", "*/file", FILES); 413516dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood URI_MATCHER.addURI("media", "*/file/#", FILES_ID); 4136e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood URI_MATCHER.addURI("media", "*/object", MTP_OBJECTS); 4137e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood URI_MATCHER.addURI("media", "*/object/#", MTP_OBJECTS_ID); 4138e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood URI_MATCHER.addURI("media", "*/object/#/references", MTP_OBJECT_REFERENCES); 4139b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 4140a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen /** 4141a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen * @deprecated use the 'basic' or 'fancy' search Uris instead 4142a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen */ 4143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY, 4144a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 4145702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 4146a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 4147a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 4148a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used for search suggestions 4149a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY, 4150a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_BASIC); 4151a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY + 4152a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "/*", AUDIO_SEARCH_BASIC); 4153a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 4154a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used by the music app's search activity 4155a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy", AUDIO_SEARCH_FANCY); 4156a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy/*", AUDIO_SEARCH_FANCY); 4157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project} 4159