MediaProvider.java revision 24001394f571b1f0378840cbf299288e4df10508
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; 46702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.net.Uri; 47702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Binder; 48702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Environment; 49702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.FileUtils; 50702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Handler; 51ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Changimport android.os.HandlerThread; 52702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Message; 53702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.ParcelFileDescriptor; 54702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Process; 55d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwoodimport android.os.RemoteException; 56702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.BaseColumns; 57702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore; 58702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Audio; 59702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Images; 60702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.MediaColumns; 61702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Video; 62702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Images.ImageColumns; 63b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwoodimport android.provider.MediaStore.MtpObjects; 64b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwoodimport android.provider.MediaStore.MtpObjects.ObjectColumns; 65b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwoodimport android.provider.Mtp; 66702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.text.TextUtils; 67702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.util.Log; 68702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 69702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.File; 70702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileInputStream; 71702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileNotFoundException; 72702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.IOException; 73702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.OutputStream; 74702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.text.Collator; 75cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissenimport java.util.ArrayList; 76702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashMap; 77702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashSet; 78702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.Iterator; 79f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissenimport java.util.List; 80b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport java.util.PriorityQueue; 818a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huberimport java.util.Stack; 82702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 83702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project/** 84702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Media content provider. See {@link android.provider.MediaStore} for details. 85702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Separate databases are kept for each external storage card we see (using the 86702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * card's ID as an index). The content visible at content://media/external/... 87702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * changes with the card. 88702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 89702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectpublic class MediaProvider extends ContentProvider { 90702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri MEDIA_URI = Uri.parse("content://media"); 91702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri ALBUMART_URI = Uri.parse("content://media/external/audio/albumart"); 92b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int ALBUM_THUMB = 1; 93b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int IMAGE_THUMB = 2; 94702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 95702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final HashMap<String, String> sArtistAlbumsMap = new HashMap<String, String>(); 96d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen private static final HashMap<String, String> sFolderArtMap = new HashMap<String, String>(); 97702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 988a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A HashSet of paths that are pending creation of album art thumbnails. 998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private HashSet mPendingThumbs = new HashSet(); 1008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 1018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A Stack of outstanding thumbnail requests. 1028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private Stack mThumbRequestStack = new Stack(); 1038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 10420434e032e498b716f87cce2f23dd646819218bfRay Chen // The lock of mMediaThumbQueue protects both mMediaThumbQueue and mCurrentThumbRequest. 10520434e032e498b716f87cce2f23dd646819218bfRay Chen private MediaThumbRequest mCurrentThumbRequest = null; 106b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private PriorityQueue<MediaThumbRequest> mMediaThumbQueue = 107b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen new PriorityQueue<MediaThumbRequest>(MediaThumbRequest.PRIORITY_NORMAL, 108b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaThumbRequest.getComparator()); 109b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 110a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // For compatibility with the approximately 0 apps that used mediaprovider search in 111a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // releases 1.0, 1.1 or 1.5 112a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsLegacy = new String[] { 113a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 114a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 115a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 116a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 117a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 118a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 119a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "0 AS " + SearchManager.SUGGEST_COLUMN_ICON_2, 120a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 121a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 122a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data1 ELSE artist END AS data1", 123a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data2 ELSE " + 124a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE WHEN grouporder=2 THEN NULL ELSE album END END AS data2", 125a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "match as ar", 126a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA, 127a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "grouporder", 128ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen "NULL AS itemorder" // We should be sorting by the artist/album/title keys, but that 129ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen // column is not available here, and the list is already sorted. 130a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 131a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsFancy = new String[] { 132a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 133a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 134a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Artists.ARTIST, 135a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Albums.ALBUM, 136a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.TITLE, 137a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data1", 138a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data2", 139a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 14063f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // If this array gets changed, please update the constant below to point to the correct item. 141a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsBasic = new String[] { 142a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 143a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 144a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 145a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 146a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 147a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 148a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 149a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 15063f748ff8b258d9110038778a006b3000164fbeeSatish Sampath "(CASE WHEN grouporder=1 THEN '%1'" + // %1 gets replaced with localized string. 15163f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE CASE WHEN grouporder=3 THEN artist || ' - ' || album" + 152e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen " ELSE CASE WHEN text2!='" + MediaStore.UNKNOWN_STRING + "' THEN text2" + 15363f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE NULL END END END) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2, 154a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA 155a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 15663f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // Position of the TEXT_2 item in the above array. 15763f748ff8b258d9110038778a006b3000164fbeeSatish Sampath private final int SEARCH_COLUMN_BASIC_TEXT2 = 5; 158a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 1591717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood private static final String[] mMediaTableColumns = new String[] { 1601717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood ObjectColumns._ID, 1611717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood ObjectColumns.MEDIA_TABLE, 1621717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood ObjectColumns.MEDIA_ID, 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 201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 202702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Wrapper class for a specific database (associated with one particular 203702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * external card, or with internal storage). Can open the actual database 204702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * on demand, create and upgrade the schema, etc. 205702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 206d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private final class DatabaseHelper extends SQLiteOpenHelper { 207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final Context mContext; 208702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final boolean mInternal; // True if this is the internal database 209702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 210702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // In memory caches of artist and album data. 211702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mArtistCache = new HashMap<String, Long>(); 212702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mAlbumCache = new HashMap<String, Long>(); 213702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public DatabaseHelper(Context context, String name, boolean internal) { 215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project super(context, name, null, DATABASE_VERSION); 216702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext = context; 217702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mInternal = internal; 218702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 219702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 220702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 221702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Creates database the first time we try to open it. 222702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 223702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onCreate(final SQLiteDatabase db) { 225702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDatabase(db, mInternal, 0, DATABASE_VERSION); 226702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 227702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 228702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Updates the database format when a new content provider is used 230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * with an older database format. 231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 232702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onUpgrade(final SQLiteDatabase db, final int oldV, final int newV) { 234702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDatabase(db, mInternal, oldV, newV); 235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 237702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 238702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Touch this particular database and garbage collect old databases. 239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * An LRU cache system is used to clean up databases for old external 240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * storage volumes. 241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 243702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onOpen(SQLiteDatabase db) { 244702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mInternal) return; // The internal database is kept separately. 245702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 246d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood db.addCustomFunction("_OBJECT_REMOVED", 1, mObjectRemovedCallback); 247d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 248702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 249702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(db.getPath()); 250702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long now = System.currentTimeMillis(); 251702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(now); 252702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 253702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases if we are over the limit 254702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] databases = mContext.databaseList(); 255702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count = databases.length; 256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int limit = MAX_EXTERNAL_DATABASES; 257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete external databases that have not been used in the past two months 259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long twoMonthsAgo = now - OBSOLETE_DATABASE_DB; 260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File other = mContext.getDatabasePath(databases[i]); 262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_DATABASE_NAME.equals(databases[i]) || file.equals(other)) { 263702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.equals(other)) { 266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // reduce limit to account for the existence of the database we 267702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // are about to open, which we removed from the list. 268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project limit--; 269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 270702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = other.lastModified(); 272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (time < twoMonthsAgo) { 273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[i]); 274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[i]); 275702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 277702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 278702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 279702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 280702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 281702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases until 282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we are no longer over the limit 283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (count > limit) { 284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lruIndex = -1; 285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long lruTime = 0; 286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 287702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 288702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (databases[i] != null) { 289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = mContext.getDatabasePath(databases[i]).lastModified(); 290702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruTime == 0 || time < lruTime) { 291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruIndex = i; 292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruTime = time; 293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 296702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used database 298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruIndex != -1) { 299702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[lruIndex]); 300702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[lruIndex]); 301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[lruIndex] = null; 302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 304702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 305702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 307702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 308d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private IMtpService mMtpService; 309d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 310d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private final ServiceConnection mMtpServiceConnection = new ServiceConnection() { 311d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void onServiceConnected(ComponentName className, android.os.IBinder service) { 312d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.d(TAG, "mMtpService connected"); 313d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mMtpService = IMtpService.Stub.asInterface(service); 314d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 315d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 316d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void onServiceDisconnected(ComponentName className) { 317d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.d(TAG, "mMtpService disconnected"); 318d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mMtpService = null; 319d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 320d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood }; 321d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public boolean onCreate() { 324d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood final Context context = getContext(); 325d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 326acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums._ID, "audio.album_id AS " + 327acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums._ID); 328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM, "album"); 329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_KEY, "album_key"); 330acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.FIRST_YEAR, "MIN(year) AS " + 331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.FIRST_YEAR); 332acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.LAST_YEAR, "MAX(year) AS " + 333702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.LAST_YEAR); 334702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST, "artist"); 335702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_ID, "artist"); 336702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_KEY, "artist_key"); 337acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS, "count(*) AS " + 338acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.NUMBER_OF_SONGS); 339acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_ART, "album_art._data AS " + 340acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.ALBUM_ART); 341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 34263f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2] = 34363f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2].replaceAll( 344d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "%1", context.getString(R.string.artist_label)); 345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases = new HashMap<String, DatabaseHelper>(); 346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(INTERNAL_VOLUME); 347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project IntentFilter iFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT); 349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project iFilter.addDataScheme("file"); 350d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood context.registerReceiver(mUnmountReceiver, iFilter); 351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // open external database if external storage is mounted 353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String state = Environment.getExternalStorageState(); 354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Environment.MEDIA_MOUNTED.equals(state) || 355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(EXTERNAL_VOLUME); 357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 359ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang HandlerThread ht = new HandlerThread("thumbs thread", Process.THREAD_PRIORITY_BACKGROUND); 360ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang ht.start(); 361ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang mThumbHandler = new Handler(ht.getLooper()) { 362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void handleMessage(Message msg) { 364b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (msg.what == IMAGE_THUMB) { 365b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 36620434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest = mMediaThumbQueue.poll(); 367b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 36820434e032e498b716f87cce2f23dd646819218bfRay Chen if (mCurrentThumbRequest == null) { 369b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Log.w(TAG, "Have message but no request?"); 370b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else { 371b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen try { 37220434e032e498b716f87cce2f23dd646819218bfRay Chen File origFile = new File(mCurrentThumbRequest.mPath); 3734d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen if (origFile.exists() && origFile.length() > 0) { 37420434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.execute(); 3754d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } else { 3764d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen // original file hasn't been stored yet 3774d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen synchronized (mMediaThumbQueue) { 37820434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original file hasn't been stored yet: " + mCurrentThumbRequest.mPath); 3794d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 3804d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 381b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } catch (IOException ex) { 3821d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 3831d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen } catch (UnsupportedOperationException ex) { 3841d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // This could happen if we unplug the sd card during insert/update/delete 3851d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // See getDatabaseForUri. 3861d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 387b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } finally { 38820434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 38920434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.DONE; 39020434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 391b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 392b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 393b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 394b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else if (msg.what == ALBUM_THUMB) { 395b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ThumbData d; 396b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mThumbRequestStack) { 397b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen d = (ThumbData)mThumbRequestStack.pop(); 398b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 400b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen makeThumbInternal(d); 401b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mPendingThumbs) { 402b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen mPendingThumbs.remove(d.path); 403b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 4048a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 408d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood context.bindService(new Intent(context, MtpService.class), 409d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mMtpServiceConnection, Context.BIND_AUTO_CREATE); 410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method takes care of updating all the tables in the database to the 415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * current version, creating them if necessary. 416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method can only update databases at schema 63 or higher, which was 417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * created August 1, 2008. Older database will be cleared and recreated. 418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db Database 419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param internal True if this is the internal media database 420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDatabase(SQLiteDatabase db, boolean internal, 422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int fromVersion, int toVersion) { 423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // sanity checks 425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (toVersion != DATABASE_VERSION) { 426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Illegal update request. Got " + toVersion + ", expected " + 427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DATABASE_VERSION); 428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (fromVersion > toVersion) { 43095ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen Log.e(TAG, "Illegal update request: can't downgrade from " + fromVersion + 431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " to " + toVersion + ". Did you forget to wipe data?"); 432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 435d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // Revisions 84-86 were a failed attempt at supporting the "album artist" id3 tag. 436acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // We can't downgrade from those revisions, so start over. 437022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // (the initial change to do this was wrong, so now we actually need to start over 438022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // if the database version is 84-89) 439bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Post-gingerbread, revisions 91-94 were broken in a way that is not easy to repair. 440bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // However version 91 was reused in a divergent development path for gingerbread, 441bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // so we need to support upgrades from 91. 442bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Therefore we will only force a reset for versions 92 - 94. 443d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (fromVersion < 63 || (fromVersion >= 84 && fromVersion <= 89) || 444bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin (fromVersion >= 92 && fromVersion <= 94)) { 445acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen fromVersion = 63; 446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Drop everything and start over. 447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.i(TAG, "Upgrading media database from version " + 448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fromVersion + " to " + toVersion + ", which will destroy all old data"); 449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS images"); 450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS images_cleanup"); 451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS thumbnails"); 452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS thumbnails_cleanup"); 453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_meta"); 454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS artists"); 455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS albums"); 456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS album_art"); 457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artist_info"); 458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS album_info"); 459702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artists_albums_map"); 460702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres"); 462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres_map"); 463702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_genres_cleanup"); 464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists"); 465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists_map"); 466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_playlists_cleanup"); 467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup1"); 468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup2"); 469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS video"); 470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS video_cleanup"); 471cec8df8a90209fc4df5d1ff5f02dc364d0d2edc6Mike Lockwood db.execSQL("DROP TABLE IF EXISTS objects"); 4729ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_objects_cleanup"); 4739ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_objects_cleanup"); 4749ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_objects_cleanup"); 4759ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS playlists_objects_cleanup"); 476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS images (" + 478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "picasa_id TEXT," + 488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + 489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "orientation INTEGER," + 493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER," + 494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_id TEXT," + 495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_display_name TEXT" + 496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS mini_thumb_magic_index on images(mini_thumb_magic);"); 499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS images_cleanup DELETE ON images " + 501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM thumbnails WHERE image_id = old._id;" + 503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 506b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create image thumbnail table 507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS thumbnails (" + 508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "image_id INTEGER," + 511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "kind INTEGER," + 512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "width INTEGER," + 513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "height INTEGER" + 514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS image_id_index on thumbnails(image_id);"); 517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS thumbnails_cleanup DELETE ON thumbnails " + 519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about audio files 524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_meta (" + 525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 526216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen "_data TEXT UNIQUE NOT NULL," + 527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT NOT NULL," + 533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title_key TEXT NOT NULL," + 534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER," + 536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "composer TEXT," + 537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER," + 538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "track INTEGER," + // track is an integer to allow proper sorting 539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "year INTEGER CHECK(year!=0)," + 540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_ringtone INTEGER," + 541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_music INTEGER," + 542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_alarm INTEGER," + 543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_notification INTEGER" + 544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for artists 547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS artists (" + 548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER PRIMARY KEY," + 549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_key TEXT NOT NULL UNIQUE," + 550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT NOT NULL" + 551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 553702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for albums 554702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS albums (" + 555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_key TEXT NOT NULL UNIQUE," + 557702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT NOT NULL" + 558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS album_art (" + 561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT" + 563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 56695ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides some extra info about artists, like the number of tracks 569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and albums for this artist 570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT artist_id AS _id, artist, artist_key, " + 572acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album) AS number_of_albums, " + 573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "GROUP BY artist_key;"); 575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides extra info albums, such as the number of tracks 577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS album_info AS " + 578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT audio.album_id AS _id, album, album_key, " + 579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MIN(year) AS minyear, " + 580702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MAX(year) AS maxyear, artist, artist_id, artist_key, " + 581702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "count(*) AS " + MediaStore.Audio.Albums.NUMBER_OF_SONGS + 582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ",album_art._data AS album_art" + 583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " FROM audio LEFT OUTER JOIN album_art ON audio.album_id=album_art.album_id" + 584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " WHERE is_music=1 GROUP BY audio.album_id;"); 585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 586acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 587acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 588acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 589acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 590acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /* 592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Only external media volumes can handle genres, playlists, etc. 593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!internal) { 595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio file is deleted 596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON audio_meta " + 597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE audio_id = old._id;" + 599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE audio_id = old._id;" + 600702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio genre definitions 603702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres (" + 604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL" + 606702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 607702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contiains mappings between audio genres and audio files 609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres_map (" + 610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 612702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "genre_id INTEGER NOT NULL" + 613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio genre is delete 616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_genres_cleanup DELETE ON audio_genres " + 617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE genre_id = old._id;" + 619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio playlist definitions 622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists (" + 623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + // _data is path for file based playlists, or null 625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL," + 626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER" + 628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains mappings between audio playlists and audio files 631702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists_map (" + 632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "playlist_id INTEGER NOT NULL," + 635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "play_order INTEGER NOT NULL" + 636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio playlist is deleted 639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_playlists_cleanup DELETE ON audio_playlists " + 640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE playlist_id = old._id;" + 642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 645702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art table entry when an album is deleted 646702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup1 DELETE ON albums " + 647702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM album_art WHERE album_id = old.album_id;" + 649702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 650702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 651702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art when an album is deleted 652702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup2 DELETE ON album_art " + 653702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about video files 659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS video (" + 660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT NOT NULL," + 662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 663702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT," + 670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT," + 671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "resolution TEXT," + 672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + // for YouTube videos 674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "tags TEXT," + // for YouTube videos 675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "category TEXT," + // for YouTube videos 676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "language TEXT," + // for YouTube videos 677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_data TEXT," + 678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER" + 682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS video_cleanup DELETE ON video " + 685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // At this point the database is at least at schema version 63 (it was 691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // either created at version 63 by the code above, or was already at 692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // version 63 or later) 693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 694702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 64) { 695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 64 696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS sort_index on images(datetaken ASC, _id ASC);"); 697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 699acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 700acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.0 shipped with database version 64 701acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 702acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 65) { 704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 65 705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS titlekey_index on audio_meta(title_key);"); 706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 708403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 66, originally we updateBucketNames(db, "images"), 709403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // but we need to do it in version 89 and therefore save the update here. 710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 67) { 712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the indices that update the database to schema version 67 713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS albumkey_index on albums(album_key);"); 714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS artistkey_index on artists(artist_key);"); 715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 68) { 718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bucket_id and bucket_display_name columns for the video table. 719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_id TEXT;"); 720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_display_name TEXT"); 721403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 722403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 68, originally we updateBucketNames(db, "video"), 723403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // but we need to do it in version 89 and therefore save the update here. 724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 69) { 727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDisplayName(db, "images"); 728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 70) { 731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bookmark column for the video table. 732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bookmark INTEGER;"); 733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 73495ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 71) { 736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // There is no change to the database schema, however a code change 737702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // fixed parsing of metadata for certain files bought from the 738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // iTunes music store, so we want to rescan files that might need it. 739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We do this by clearing the modification date in the database for 740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // those files, so that the media scanner will see them as updated 741702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and rescan them. 742702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET date_modified=0 WHERE _id IN (" + 743702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _id FROM audio where mime_type='audio/mp4' AND " + 744e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "artist='" + MediaStore.UNKNOWN_STRING + "' AND " + 745e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "album='" + MediaStore.UNKNOWN_STRING + "'" + 746702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 747702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 74895ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 749702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 72) { 750702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create is_podcast and bookmark columns for the audio table. 751702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN is_podcast INTEGER;"); 752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE _data LIKE '%/podcasts/%';"); 753702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_music=0 WHERE is_podcast=1" + 754702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _data NOT LIKE '%/music/%';"); 755702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN bookmark INTEGER;"); 756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 757702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // New columns added to tables aren't visible in views on those tables 758702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // without opening and closing the database (or using the 'vacuum' command, 759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // which we can't do here because all this code runs inside a transaction). 760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // To work around this, we drop and recreate the affected view and trigger. 761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 762702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 76395ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 764acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 765acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.5 shipped with database version 72 766acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 767acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 7688d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen if (fromVersion < 73) { 7698d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // There is no change to the database schema, but we now do case insensitive 7708d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // matching of folder names when determining whether something is music, a 7718d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // ringtone, podcast, etc, so we might need to reclassify some files. 7728d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_music=1 WHERE is_music=0 AND " + 7738d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/music/%';"); 7748d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_ringtone=1 WHERE is_ringtone=0 AND " + 7758d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/ringtones/%';"); 7768d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_notification=1 WHERE is_notification=0 AND " + 7778d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/notifications/%';"); 7788d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_alarm=1 WHERE is_alarm=0 AND " + 7798d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/alarms/%';"); 7808d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE is_podcast=0 AND " + 7818d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/podcasts/%';"); 7828d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen } 783a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 784a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (fromVersion < 74) { 785a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // This view is used instead of the audio view by the union below, to force 786a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // sqlite to use the title_key index. This greatly reduces memory usage 787a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // (no separate copy pass needed for sorting, which could cause errors on 788a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // large datasets) and improves speed (by about 35% on a large dataset) 789a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS searchhelpertitle AS SELECT * FROM audio " + 790a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "ORDER BY title_key;"); 791a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 792a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS search AS " + 793a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 794a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'artist' AS mime_type," + 795a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 796a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS album," + 797a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 798a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text1," + 799a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS text2," + 800a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_albums AS data1," + 801a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_tracks AS data2," + 802a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key AS match," + 803a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/artists/'||_id AS suggest_intent_data," + 804a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "1 AS grouporder " + 805e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM artist_info WHERE (artist!='" + MediaStore.UNKNOWN_STRING + "') " + 806a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 807a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 808a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'album' AS mime_type," + 809a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 810a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 811a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 812a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album AS text1," + 813a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 814a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 815a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 816a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key AS match," + 817a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/albums/'||_id AS suggest_intent_data," + 818a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "2 AS grouporder " + 819e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM album_info WHERE (album!='" + MediaStore.UNKNOWN_STRING + "') " + 820a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 821a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT searchhelpertitle._id AS _id," + 822a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "mime_type," + 823a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 824a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 825a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title," + 826a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title AS text1," + 827a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 828a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 829a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 830a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key||' '||title_key AS match," + 831a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/media/'||searchhelpertitle._id AS " + 832a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "suggest_intent_data," + 833a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "3 AS grouporder " + 834a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "FROM searchhelpertitle WHERE (title != '') " 835a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ); 836a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } 83759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 83859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (fromVersion < 75) { 83995ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen // Force a rescan of the audio entries so we can apply the new logic to 84059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // distinguish same-named albums. 84159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 84259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("DELETE FROM albums"); 84359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 84415d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen 84515d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen if (fromVersion < 76) { 84615d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // We now ignore double quotes when building the key, so we have to remove all of them 84715d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // from existing keys. 84815d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE audio_meta SET title_key=" + 84915d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(title_key,x'081D08C29F081D',x'081D') " + 85015d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE title_key LIKE '%'||x'081D08C29F081D'||'%';"); 85115d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE albums SET album_key=" + 85215d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(album_key,x'081D08C29F081D',x'081D') " + 85315d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE album_key LIKE '%'||x'081D08C29F081D'||'%';"); 85415d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE artists SET artist_key=" + 85515d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(artist_key,x'081D08C29F081D',x'081D') " + 85615d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE artist_key LIKE '%'||x'081D08C29F081D'||'%';"); 85715d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen } 858b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 859acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 860acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.6 shipped with database version 76 861acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 862acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 863b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (fromVersion < 77) { 864b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create video thumbnail table 865b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TABLE IF NOT EXISTS videothumbnails (" + 866b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_id INTEGER PRIMARY KEY," + 867b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_data TEXT," + 868b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "video_id INTEGER," + 869b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "kind INTEGER," + 870b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "width INTEGER," + 871b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "height INTEGER" + 872b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ");"); 873b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 874b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE INDEX IF NOT EXISTS video_id_index on videothumbnails(video_id);"); 875b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 876b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TRIGGER IF NOT EXISTS videothumbnails_cleanup DELETE ON videothumbnails " + 877b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "BEGIN " + 878b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "SELECT _DELETE_FILE(old._data);" + 879b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "END"); 880b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 8811769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen 882acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 883acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.0 and 2.0.1 shipped with database version 77 884acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 885acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 8861769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen if (fromVersion < 78) { 887044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force a rescan of the video entries so we can update 8881769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen // latest changed DATE_TAKEN units (in milliseconds). 8891769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen db.execSQL("UPDATE video SET date_modified=0;"); 8901769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen } 891268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 892acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 893acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.1 shipped with database version 78 894acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 895acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 896268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (fromVersion < 79) { 897268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move /sdcard/albumthumbs to 898268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // /sdcard/Android/data/com.android.providers.media/albumthumbs, 899268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // and update the database accordingly 900268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 901268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen String storageroot = Environment.getExternalStorageDirectory().getAbsolutePath(); 902268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen String oldthumbspath = storageroot + "/albumthumbs"; 903268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen String newthumbspath = storageroot + "/" + ALBUM_THUMB_FOLDER; 904268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File thumbsfolder = new File(oldthumbspath); 905268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (thumbsfolder.exists()) { 906268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move folder to its new location 907268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File newthumbsfolder = new File(newthumbspath); 908268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen newthumbsfolder.getParentFile().mkdirs(); 909268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if(thumbsfolder.renameTo(newthumbsfolder)) { 910268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // update the database 911268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen db.execSQL("UPDATE album_art SET _data=REPLACE(_data, '" + 912268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen oldthumbspath + "','" + newthumbspath + "');"); 913268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 914268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 915268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 916044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen 917044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen if (fromVersion < 80) { 918044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force rescan of image entries to update DATE_TAKEN as UTC timestamp. 919044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen db.execSQL("UPDATE images SET date_modified=0;"); 920044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen } 9210ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 922166a4e3cc66a645cc5e11d2f06d059512def0aceMarco Nelissen if (fromVersion < 81 && !internal) { 9230ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete entries starting with /mnt/sdcard. This is for the benefit 9240ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // of users running builds between 2.0.1 and 2.1 final only, since 9250ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // users updating from 2.0 or earlier will not have such entries. 9260ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 9270ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // First we need to update the _data fields in the affected tables, since 9280ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // otherwise deleting the entries will also delete the underlying files 9290ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // (via a trigger), and we want to keep them. 9300ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 9310ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 9320ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 9330ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 9340ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 9350ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 936216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("UPDATE audio_meta SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 9370ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Once the paths have been renamed, we can safely delete the entries 9380ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_playlists WHERE _data IS '////';"); 9390ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM images WHERE _data IS '////';"); 9400ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM video WHERE _data IS '////';"); 9410ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM videothumbnails WHERE _data IS '////';"); 9420ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM thumbnails WHERE _data IS '////';"); 9430ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_meta WHERE _data IS '////';"); 9440ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM album_art WHERE _data IS '////';"); 9450ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 9460ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // rename existing entries starting with /sdcard to /mnt/sdcard 9470ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta" + 9480ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 9490ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists" + 9500ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 9510ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images" + 9520ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 9530ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video" + 9540ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 9550ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails" + 9560ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 9570ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails" + 9580ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 9590ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art" + 9600ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 9610ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 9620ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete albums and artists, then clear the modification time on songs, which 9630ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // will cause the media scanner to rescan everything, rebuilding the artist and 9640ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // album tables along the way, while preserving playlists. 9650ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // We need this rescan because ICU also changed, and now generates different 9660ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // collation keys 9670ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from albums"); 9680ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from artists"); 9690ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 9700ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen } 97184403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen 97284403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen if (fromVersion < 82) { 973acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // recreate this view with the correct "group by" specifier 97484403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("DROP VIEW IF EXISTS artist_info"); 97584403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 97684403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "SELECT artist_id AS _id, artist, artist_key, " + 977acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album_key) AS number_of_albums, " + 97884403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 97984403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "GROUP BY artist_key;"); 98084403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen } 981216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 982acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* we skipped over version 83, and reverted versions 84, 85 and 86 */ 983ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen 984ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen if (fromVersion < 87) { 985ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // The fastscroll thumb needs an index on the strings being displayed, 986ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // otherwise the queries it does to determine the correct position 987ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // becomes really inefficient 988022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS title_idx on audio_meta(title);"); 989022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_idx on artists(artist);"); 990022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_idx on albums(album);"); 991ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } 992216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 993acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen if (fromVersion < 88) { 994acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // Clean up a few more things from versions 84/85/86, and recreate 995acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // the few things worth keeping from those changes. 996acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update1;"); 997acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update2;"); 998acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update3;"); 999acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update4;"); 1000acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update1;"); 1001acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update2;"); 1002acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update3;"); 1003acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update4;"); 1004acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP VIEw IF EXISTS album_artists;"); 1005acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_id_idx on audio_meta(album_id);"); 1006acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_id_idx on audio_meta(artist_id);"); 1007acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 1008acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 1009acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 1010acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 1011acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen } 1012403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 1013403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen if (fromVersion < 89) { 1014403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen updateBucketNames(db, "images"); 1015403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen updateBucketNames(db, "video"); 1016403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen } 1017b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 1018b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (fromVersion < 91) { 1019b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // A table containing information for all files, 1020b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // needed for MTP support 1021b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood db.execSQL("CREATE TABLE IF NOT EXISTS objects (" + 1022b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood "_id INTEGER PRIMARY KEY," + 1023b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood "_data TEXT NOT NULL," + 1024b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood "_size INTEGER," + 1025b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood "format INTEGER," + 1026b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood "parent INTEGER," + 1027cec8df8a90209fc4df5d1ff5f02dc364d0d2edc6Mike Lockwood "date_modified INTEGER," + 1028d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // ID of the media table for this object. 1029d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // Possible values are IMAGES_MEDIA, AUDIO_MEDIA, and VIDEO_MEDIA 1030d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // and AUDIO_PLAYLISTS. 1031cec8df8a90209fc4df5d1ff5f02dc364d0d2edc6Mike Lockwood "media_table INTEGER," + 1032d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // The row number of this object in the corresponding media table. 1033d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "media_id INTEGER" + 1034b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood ");"); 10359ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood 1036d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // Add cross reference from media table to MTP object table 1037d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // Object ID is the row number of this object in the "objects" table 1038d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood db.execSQL("ALTER TABLE images ADD COLUMN object_id INTEGER;"); 1039d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood db.execSQL("ALTER TABLE audio_meta ADD COLUMN object_id INTEGER;"); 1040d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood db.execSQL("ALTER TABLE video ADD COLUMN object_id INTEGER;"); 1041d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (!internal) { 1042d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // audio_playlists does not exist in internal database 1043d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood db.execSQL("ALTER TABLE audio_playlists ADD COLUMN object_id INTEGER;"); 1044d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 1045d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // cleans up objects table when an image file is deleted 1046d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS images_objects_cleanup DELETE ON images " + 1047d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "BEGIN " + 1048d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "DELETE FROM objects WHERE _id = old.object_id;" + 1049d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "SELECT _OBJECT_REMOVED(old.object_id);" + 1050d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "END"); 10519ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood 1052d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // cleans up objects table when an audio file is deleted 1053d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_objects_cleanup DELETE ON audio_meta " + 1054d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "BEGIN " + 1055d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "DELETE FROM objects WHERE _id = old.object_id;" + 1056d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "SELECT _OBJECT_REMOVED(old.object_id);" + 1057d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "END"); 10589ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood 1059d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // cleans up objects table when a video file is deleted 1060d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS video_objects_cleanup DELETE ON video " + 1061d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "BEGIN " + 1062d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "DELETE FROM objects WHERE _id = old.object_id;" + 1063d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "SELECT _OBJECT_REMOVED(old.object_id);" + 1064d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "END"); 10659ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood 1066d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // cleans up objects table when a playlist file is deleted 1067d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS playlists_objects_cleanup DELETE ON audio_playlists " + 1068d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "BEGIN " + 1069d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "DELETE FROM objects WHERE _id = old.object_id;" + 1070d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "SELECT _OBJECT_REMOVED(old.object_id);" + 1071d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "END"); 1072d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 10739ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood } 1074bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin 1075bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // This was actually added in version 91 in gingerbread, but during post-gingerbread development 1076bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // it was not added until version 96. 1077bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin if (fromVersion < 96) { 1078bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Never query by mini_thumb_magic_index 1079bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("DROP INDEX IF EXISTS mini_thumb_magic_index"); 1080bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin 1081bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // sort the items by taken date in each bucket 1082bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("CREATE INDEX IF NOT EXISTS image_bucket_index ON images(bucket_id, datetaken)"); 1083bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("CREATE INDEX IF NOT EXISTS video_bucket_index ON video(bucket_id, datetaken)"); 1084bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin } 1085bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin 1086acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sanityCheck(db, fromVersion); 10871d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen } 10881d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen 10891d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen /** 1090216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * Perform a simple sanity check on the database. Currently this tests 1091216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * whether all the _data entries in audio_meta are unique 1092216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen */ 1093216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen private static void sanityCheck(SQLiteDatabase db, int fromVersion) { 1094216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c1 = db.query("audio_meta", new String[] {"count(*)"}, 1095216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 1096216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c2 = db.query("audio_meta", new String[] {"count(distinct _data)"}, 1097216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 1098216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.moveToFirst(); 1099216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.moveToFirst(); 1100216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num1 = c1.getInt(0); 1101216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num2 = c2.getInt(0); 1102216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.close(); 1103216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.close(); 1104216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (num1 != num2) { 1105216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Log.e(TAG, "audio_meta._data column is not unique while upgrading" + 1106216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen " from schema " +fromVersion + " : " + num1 +"/" + num2); 1107216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen // Delete all audio_meta rows so they will be rebuilt by the media scanner 1108216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("DELETE FROM audio_meta;"); 1109216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 1110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void recreateAudioView(SQLiteDatabase db) { 1113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides a unified audio/artist/album info view. 1114702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note that views are read-only, so we define a trigger to allow deletes. 1115702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS audio"); 1116702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_delete"); 1117702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS audio as SELECT * FROM audio_meta " + 1118702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN artists ON audio_meta.artist_id=artists.artist_id " + 1119702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN albums ON audio_meta.album_id=albums.album_id;"); 1120702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1121702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_delete INSTEAD OF DELETE ON audio " + 1122702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 1123702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_meta where _id=old._id;" + 1124702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_playlists_map where audio_id=old._id;" + 1125702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_genres_map where audio_id=old._id;" + 1126702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 1127702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 112895ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 1129702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1130702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the bucket_id and 1131702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * bucket_display_name columns are correct. 1132702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 1133702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 1134702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1135702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateBucketNames(SQLiteDatabase db, String tableName) { 1136702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Rebuild the bucket_display_name column using the natural case rather than lower case. 1137702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1138702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA}; 1140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 1141702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1142702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 1144702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1145702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 1146702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(); 1147702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 1148702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int rowId = cursor.getInt(idColumnIndex); 1149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(tableName, values, "_id=" + rowId, null); 1150702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1152702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1153702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1154702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1155702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the 1162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * display name column has a value. 1163702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 1164702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 1165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDisplayName(SQLiteDatabase db, String tableName) { 1167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Fill in default values for null displayName values 1168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1169702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA, MediaColumns.DISPLAY_NAME}; 1171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 1172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 1175702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int displayNameIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME); 1176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(); 1177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String displayName = cursor.getString(displayNameIndex); 1179702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (displayName == null) { 1180702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 1181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.clear(); 1182702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 1183702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int rowId = cursor.getInt(idColumnIndex); 1184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(tableName, values, "_id=" + rowId, null); 1185702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1186702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1187702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1188702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1191702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1193702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1194702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1195702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1196702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1197702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the bucked id name and bucket display name are updated. 1198702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1199702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1200702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeBucketValues(String data, ContentValues values) { 1202702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File parentFile = new File(data).getParentFile(); 1203702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (parentFile == null) { 1204702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project parentFile = new File("/"); 1205702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1206702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Lowercase the path for hashing. This avoids duplicate buckets if the 1208702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // filepath case is changed externally. 1209702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Keep the original case for display. 1210702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path = parentFile.toString().toLowerCase(); 1211702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = parentFile.getName(); 1212702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1213702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note: the BUCKET_ID and BUCKET_DISPLAY_NAME attributes are spelled the 1214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // same for both images and video. However, for backwards-compatibility reasons 1215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // there is no common base class. We use the ImageColumns version here 1216702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(ImageColumns.BUCKET_ID, path.hashCode()); 1217702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(ImageColumns.BUCKET_DISPLAY_NAME, name); 1218702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1219702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1220702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1221702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1222702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the display name is updated. 1223702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1225702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeDisplayName(String data, ContentValues values) { 1226702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = (data == null ? "" : data.toString()); 1227702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int idx = s.lastIndexOf('/'); 1228702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (idx >= 0) { 1229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = s.substring(idx + 1); 1230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("_display_name", s); 1232702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1234b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen /** 1235498b62c2912302a23532c73a028a7684c5df33caRay Chen * Copy taken time from date_modified if we lost the original value (e.g. after factory reset) 1236498b62c2912302a23532c73a028a7684c5df33caRay Chen * This works for both video and image tables. 1237b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * 1238b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * @param values the content values, where taken time is updated. 1239b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen */ 1240b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen private static void computeTakenTime(ContentValues values) { 1241b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (! values.containsKey(Images.Media.DATE_TAKEN)) { 1242b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // This only happens when MediaScanner finds an image file that doesn't have any useful 1243b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // reference to get this value. (e.g. GPSTimeStamp) 1244498b62c2912302a23532c73a028a7684c5df33caRay Chen Long lastModified = values.getAsLong(MediaColumns.DATE_MODIFIED); 1245b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (lastModified != null) { 1246b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen values.put(Images.Media.DATE_TAKEN, lastModified * 1000); 1247b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1248b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1249b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1250b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen 1251b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen /** 1252b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * This method blocks until thumbnail is ready. 1253b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * 1254b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @param thumbUri 1255b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @return 1256b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen */ 1257b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean waitForThumbnailReady(Uri origUri) { 1258b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Cursor c = this.query(origUri, new String[] { ImageColumns._ID, ImageColumns.DATA, 1259b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ImageColumns.MINI_THUMB_MAGIC}, null, null, null); 1260b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c == null) return false; 1261b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1262b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean result = false; 1263b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1264b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c.moveToFirst()) { 1265e263c2a4b880ef8a5314bb4379c74bf5f9292bd0Ray Chen long id = c.getLong(0); 1266b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String path = c.getString(1); 1267b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen long magic = c.getLong(2); 1268b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 12699299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest req = requestMediaThumbnail(path, origUri, 12709299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest.PRIORITY_HIGH, magic); 12719299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req == null) { 12729299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen return false; 12739299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 12749299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen synchronized (req) { 12759299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen try { 12769299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen while (req.mState == MediaThumbRequest.State.WAIT) { 12779299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen req.wait(); 127820434e032e498b716f87cce2f23dd646819218bfRay Chen } 12799299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } catch (InterruptedException e) { 12809299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen Log.w(TAG, e); 12819299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 12829299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req.mState == MediaThumbRequest.State.DONE) { 12839299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen result = true; 1284b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1285b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1286b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1287b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen c.close(); 1288b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1289b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return result; 1290b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1291b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1292e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen private boolean matchThumbRequest(MediaThumbRequest req, int pid, long id, long gid, 1293e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo) { 1294e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllOrigId = (id == -1); 1295e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllGroupId = (gid == -1); 1296e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen return (req.mCallingPid == pid) && 1297e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllGroupId || req.mGroupId == gid) && 1298e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllOrigId || req.mOrigId == id) && 1299e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (req.mIsVideo == isVideo); 1300e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 1301e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 1302b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean queryThumbnail(SQLiteQueryBuilder qb, Uri uri, String table, 1303b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String column, boolean hasThumbnailId) { 1304b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.setTables(table); 1305b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (hasThumbnailId) { 1306b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // For uri dispatched to this method, the 4th path segment is always 1307b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // the thumbnail id. 1308b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere("_id = " + uri.getPathSegments().get(3)); 1309b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // client already knows which thumbnail it wants, bypass it. 1310b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1311b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1312b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String origId = uri.getQueryParameter("orig_id"); 1313b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // We can't query ready_flag unless we know original id 1314b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId == null) { 1315b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // this could be thumbnail query for other purpose, bypass it. 1316b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1317b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1318b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1319b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean needBlocking = "1".equals(uri.getQueryParameter("blocking")); 132020434e032e498b716f87cce2f23dd646819218bfRay Chen boolean cancelRequest = "1".equals(uri.getQueryParameter("cancel")); 1321e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Uri origUri = uri.buildUpon().encodedPath( 1322e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen uri.getPath().replaceFirst("thumbnails", "media")) 1323e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen .appendPath(origId).build(); 1324b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1325b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (needBlocking && !waitForThumbnailReady(origUri)) { 132620434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original media doesn't exist or it's canceled."); 1327b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return false; 132820434e032e498b716f87cce2f23dd646819218bfRay Chen } else if (cancelRequest) { 1329e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen String groupId = uri.getQueryParameter("group_id"); 1330e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo = "video".equals(uri.getPathSegments().get(1)); 133120434e032e498b716f87cce2f23dd646819218bfRay Chen int pid = Binder.getCallingPid(); 133220434e032e498b716f87cce2f23dd646819218bfRay Chen long id = -1; 1333e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen long gid = -1; 1334e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 133520434e032e498b716f87cce2f23dd646819218bfRay Chen try { 133620434e032e498b716f87cce2f23dd646819218bfRay Chen id = Long.parseLong(origId); 1337e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen gid = Long.parseLong(groupId); 133820434e032e498b716f87cce2f23dd646819218bfRay Chen } catch (NumberFormatException ex) { 133920434e032e498b716f87cce2f23dd646819218bfRay Chen // invalid cancel request 134020434e032e498b716f87cce2f23dd646819218bfRay Chen return false; 134120434e032e498b716f87cce2f23dd646819218bfRay Chen } 1342e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 134320434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mMediaThumbQueue) { 1344e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (mCurrentThumbRequest != null && 1345e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen matchThumbRequest(mCurrentThumbRequest, pid, id, gid, isVideo)) { 134620434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 134720434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.CANCEL; 134820434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 134920434e032e498b716f87cce2f23dd646819218bfRay Chen } 135020434e032e498b716f87cce2f23dd646819218bfRay Chen } 135120434e032e498b716f87cce2f23dd646819218bfRay Chen for (MediaThumbRequest mtq : mMediaThumbQueue) { 1352e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (matchThumbRequest(mtq, pid, id, gid, isVideo)) { 135320434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mtq) { 135420434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.mState = MediaThumbRequest.State.CANCEL; 135520434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.notifyAll(); 135620434e032e498b716f87cce2f23dd646819218bfRay Chen } 135720434e032e498b716f87cce2f23dd646819218bfRay Chen 135820434e032e498b716f87cce2f23dd646819218bfRay Chen mMediaThumbQueue.remove(mtq); 135920434e032e498b716f87cce2f23dd646819218bfRay Chen } 136020434e032e498b716f87cce2f23dd646819218bfRay Chen } 136120434e032e498b716f87cce2f23dd646819218bfRay Chen } 1362b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1363b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1364b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId != null) { 1365b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere(column + " = " + origId); 1366b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1367b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1368b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1369b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen @SuppressWarnings("fallthrough") 1370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Cursor query(Uri uri, String[] projectionIn, String selection, 1372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] selectionArgs, String sort) { 1373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int table = URI_MATCHER.match(uri); 1374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 137501a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // Log.v(TAG, "query: uri="+uri+", selection="+selection); 1376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 1377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (table == MEDIA_SCANNER) { 1378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 1379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 1380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1381702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a cursor to return volume currently being scanned by the media scanner 13820027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {MediaStore.MEDIA_SCANNER_VOLUME}); 13830027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new String[] {mMediaScannerVolume}); 13840027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 1385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1386702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1387702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 13880027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // Used temporarily (until we have unique media IDs) to get an identifier 13890027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // for the current sd card, so that the music app doesn't have to use the 13900027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // non-public getFatVolumeId method 13910027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen if (table == FS_ID) { 13920027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {"fsid"}); 13930027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new Integer[] {mVolumeId}); 13940027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 13950027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen } 13960027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 1397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String groupBy = null; 1398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 1399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 1400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 1401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getReadableDatabase(); 1403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 14044574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit = uri.getQueryParameter("limit"); 1405b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean hasThumbnailId = false; 1406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (table) { 1408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 1409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 1410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 1411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 1412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 1414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 1415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 1418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 1419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 1420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 1421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 1423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 1424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id = " + uri.getPathSegments().get(3)); 1425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 1428b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 1429b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 1430b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "thumbnails", "image_id", hasThumbnailId)) { 1431b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 1432b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 1436d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 1437ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.equalsIgnoreCase("is_music=1") 1438ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen || selection.equalsIgnoreCase("is_podcast=1") ) 1439ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") ) { 1440ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting songs"); 1441ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 1442ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 1443ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio"); 1444ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 1445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 1448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 1453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT genre_id FROM " + 1455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map WHERE audio_id = " + 1456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1459702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 1460702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1463702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 1465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT playlist_id FROM " + 1467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_playlists_map WHERE audio_id = " + 1468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 1472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 1477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 1481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 1486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT audio_id FROM " + 1488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map WHERE genre_id = " + 1489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 1493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 1498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 1502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1506702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 150797e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen if (projectionIn != null) { 150897e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen for (int i = 0; i < projectionIn.length; i++) { 150997e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen if (projectionIn[i].equals("_id")) { 151097e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen projectionIn[i] = "audio_playlists_map._id AS _id"; 151197e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen } 1512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists_map, audio"); 1515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("audio._id = audio_id AND playlist_id = " 1516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project + uri.getPathSegments().get(3)); 1517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 1520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 1525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 1526bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin if (uri.getQueryParameter("distinct") != null) { 1527bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin qb.setDistinct(true); 1528bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin } 1529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 1531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 1532bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin if (uri.getQueryParameter("distinct") != null) { 1533bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin qb.setDistinct(true); 1534bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin } 1535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1538b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 1539b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 1540b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 1541b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "videothumbnails", "video_id", hasThumbnailId)) { 1542b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 1543b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1544b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 1545b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS: 1547d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 1548ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 1549ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") ) { 1550ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting artists"); 1551ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 1552ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct artist_id)"; 1553ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 1554ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 1555ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("artist_info"); 1556ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 1557702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID: 1560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("artist_info"); 1561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID_ALBUMS: 1565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String aid = uri.getPathSegments().get(3); 1566acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.setTables("audio LEFT OUTER JOIN album_art ON" + 1567acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen " audio.album_id=album_art.album_id"); 1568acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.appendWhere("is_music=1 AND audio.album_id IN (SELECT album_id FROM " + 1569acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "artists_albums_map WHERE artist_id = " + 1570acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen aid + ")"); 1571acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen groupBy = "audio.album_id"; 1572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST, 1573acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "count(CASE WHEN artist_id==" + aid + " THEN 'foo' ELSE NULL END) AS " + 1574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST); 1575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setProjectionMap(sArtistAlbumsMap); 1576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS: 1579d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 1580ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 1581ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") ) { 1582ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting albums"); 1583ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 1584ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct album_id)"; 1585ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 1586ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 1587ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("album_info"); 1588ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 1589702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1590702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS_ID: 1592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_info"); 1593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 1597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_art"); 1598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("album_id=" + uri.getPathSegments().get(3)); 1599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1600702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1601a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_LEGACY: 1602a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen Log.w(TAG, "Legacy media search Uri used. Please update your code."); 1603a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // fall through 1604a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_FANCY: 1605a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_BASIC: 1606a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen return doAudioSearch(db, qb, uri, projectionIn, selection, selectionArgs, sort, 16074574e03055af60fada50481f2b34e19a687d5866Marco Nelissen table, limit); 1608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1609b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood case MTP_OBJECTS_ID: 1610b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood qb.appendWhere("_id=" + uri.getPathSegments().get(2)); 1611b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // fall through 1612b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood case MTP_OBJECTS: 1613b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood qb.setTables("objects"); 1614b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood break; 1615b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 1616e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood case MTP_OBJECT_REFERENCES: 1617e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int handle = Integer.parseInt(uri.getPathSegments().get(2)); 1618e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return getObjectReferences(db, handle); 1619e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 1620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 1621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unknown URL: " + uri.toString()); 1622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 16244d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen // Log.v(TAG, "query = "+ qb.buildQuery(projectionIn, selection, selectionArgs, groupBy, null, sort, limit)); 1625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, projectionIn, selection, 16264574e03055af60fada50481f2b34e19a687d5866Marco Nelissen selectionArgs, groupBy, null, sort, limit); 1627b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) { 1629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.setNotificationUri(getContext().getContentResolver(), uri); 1630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1631b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return c; 1633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Cursor doAudioSearch(SQLiteDatabase db, SQLiteQueryBuilder qb, 1636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri, String[] projectionIn, String selection, 16374574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String[] selectionArgs, String sort, int mode, 16384574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit) { 1639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 164018c787fb045725bf10bf630ac0917a48def9ace5Marco Nelissen String mSearchString = uri.getPath().endsWith("/") ? "" : uri.getLastPathSegment(); 1641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString = mSearchString.replaceAll(" ", " ").trim().toLowerCase(); 1642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] searchWords = mSearchString.length() > 0 ? 1644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString.split(" ") : new String[0]; 1645a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] wildcardWords = new String[searchWords.length]; 1646702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Collator col = Collator.getInstance(); 1647702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project col.setStrength(Collator.PRIMARY); 1648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = searchWords.length; 1649702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 1650702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Because we match on individual words here, we need to remove words 1651702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // like 'a' and 'the' that aren't part of the keys. 16523001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen String key = MediaStore.Audio.keyFor(searchWords[i]); 16533001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("\\", "\\\\"); 16543001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("%", "\\%"); 16553001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("_", "\\_"); 1656a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen wildcardWords[i] = 1657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project (searchWords[i].equals("a") || searchWords[i].equals("an") || 16583001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen searchWords[i].equals("the")) ? "%" : "%" + key + "%"; 1659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1661a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String where = ""; 1662a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen for (int i = 0; i < searchWords.length; i++) { 1663a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (i == 0) { 16643001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen where = "match LIKE ? ESCAPE '\\'"; 1665a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 16663001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen where += " AND match LIKE ? ESCAPE '\\'"; 1667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1670a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen qb.setTables("search"); 1671a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] cols; 1672a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (mode == AUDIO_SEARCH_FANCY) { 1673a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsFancy; 1674a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else if (mode == AUDIO_SEARCH_BASIC) { 1675a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsBasic; 1676a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 1677a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsLegacy; 1678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 16794574e03055af60fada50481f2b34e19a687d5866Marco Nelissen return qb.query(db, cols, where, wildcardWords, null, null, null, limit); 1680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String getType(Uri url) 1684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 1685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (URI_MATCHER.match(url)) { 1686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 1687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 1688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 1689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 1690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 169126f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen Cursor c = null; 169226f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen try { 169326f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c = query(url, MIME_TYPE_PROJECTION, null, null, null); 169426f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null && c.getCount() == 1) { 169526f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.moveToFirst(); 169626f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen String mimeType = c.getString(1); 169726f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.deactivate(); 169826f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen return mimeType; 169926f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 170026f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } finally { 170126f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null) { 170226f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.close(); 170326f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 1704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 1708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: 1709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Images.Media.CONTENT_TYPE; 1710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 1711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return "image/jpeg"; 1712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 1714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 1715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 1716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Media.CONTENT_TYPE; 1717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 1719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 1720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.CONTENT_TYPE; 1721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 1722702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 1723702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.ENTRY_CONTENT_TYPE; 1724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 1725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 1726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.CONTENT_TYPE; 1727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 1728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 1729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.ENTRY_CONTENT_TYPE; 1730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 1732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Video.Media.CONTENT_TYPE; 1733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unknown URL"); 1735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1737702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Ensures there is a file in the _data column of values, if one isn't 1739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * present a new file is created. 1740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1741702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param initialValues the values passed to insert by the caller 1742702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the new values 1743702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1744702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private ContentValues ensureFile(boolean internal, ContentValues initialValues, 1745702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String preferredExtension, String directoryName) { 1746702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values; 1747702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String file = initialValues.getAsString("_data"); 1748702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (TextUtils.isEmpty(file)) { 1749702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file = generateFileName(internal, preferredExtension, directoryName); 1750702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = new ContentValues(initialValues); 1751702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("_data", file); 1752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1753702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = initialValues; 1754702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1755702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!ensureFileExists(file)) { 1757702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unable to create new file: " + file); 1758702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return values; 1760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1762d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private void sendObjectAdded(long objectHandle) { 1763d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood IMtpService mtpService = mMtpService; 1764d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mtpService != null) { 1765d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood try { 1766d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mtpService.sendObjectAdded((int)objectHandle); 1767d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } catch (RemoteException e) { 1768d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.e(TAG, "RemoteException in sendObjectAdded", e); 1769d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 1770d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 1771d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 1772d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 1773d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private void sendObjectRemoved(long objectHandle) { 1774d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood IMtpService mtpService = mMtpService; 1775d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mtpService != null) { 1776d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood try { 1777d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mtpService.sendObjectRemoved((int)objectHandle); 1778d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } catch (RemoteException e) { 1779d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.e(TAG, "RemoteException in sendObjectRemoved", e); 1780d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 1781d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 1782d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 1783d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 1784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int bulkInsert(Uri uri, ContentValues values[]) { 1786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 1787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == VOLUMES) { 1788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return super.bulkInsert(uri, values); 1789702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1790702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 1791702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 1792702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 1793702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 1794702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1795702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 1796ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 1797ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen if (match == AUDIO_PLAYLISTS_ID || match == AUDIO_PLAYLISTS_ID_MEMBERS) { 1798ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return playlistBulkInsert(db, uri, values); 1799e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } else if (match == MTP_OBJECT_REFERENCES) { 1800e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int handle = Integer.parseInt(uri.getPathSegments().get(2)); 1801e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return setObjectReferences(db, handle, values); 1802ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 1803ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 1804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1805702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int numInserted = 0; 1806702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = values.length; 1808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 18095d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood insertInternal(uri, match, values[i]); 1810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project numInserted = len; 1812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 1817702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return numInserted; 1818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1819702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Uri insert(Uri uri, ContentValues initialValues) 1822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 18235d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood int match = URI_MATCHER.match(uri); 18245d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood Uri newUri = insertInternal(uri, match, initialValues); 18255d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood // do not signal notification for MTP objects. 18265d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood // we will signal instead after file transfer is successful. 18275d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (newUri != null && match != MTP_OBJECTS) { 1828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 1829702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1830702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 1831702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1832702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1833ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen private int playlistBulkInsert(SQLiteDatabase db, Uri uri, ContentValues values[]) { 1834ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen DatabaseUtils.InsertHelper helper = 1835ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen new DatabaseUtils.InsertHelper(db, "audio_playlists_map"); 18368b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int audioidcolidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID); 18378b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playlistididx = helper.getColumnIndex(Audio.Playlists.Members.PLAYLIST_ID); 18388b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorderidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.PLAY_ORDER); 18398b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 1840ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 1841ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.beginTransaction(); 1842ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int numInserted = 0; 1843ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen try { 1844ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int len = values.length; 1845ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen for (int i = 0; i < len; i++) { 18468b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.prepareForInsert(); 18478b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // getting the raw Object and converting it long ourselves saves 18488b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // an allocation (the alternative is ContentValues.getAsLong, which 18498b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // returns a Long object) 18508b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long audioid = ((Number) values[i].get( 18518b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.AUDIO_ID)).longValue(); 18528b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(audioidcolidx, audioid); 18538b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playlistididx, playlistId); 18548b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // convert to int ourselves to save an allocation. 18558b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorder = ((Number) values[i].get( 18568b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.PLAY_ORDER)).intValue(); 18578b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playorderidx, playorder); 18588b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.execute(); 1859ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 1860ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen numInserted = len; 1861ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.setTransactionSuccessful(); 1862ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } finally { 1863ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.endTransaction(); 1864ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen helper.close(); 1865ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 1866ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 1867ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return numInserted; 1868ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 1869ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 1870b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood private long getParent(SQLiteDatabase db, String path) { 1871b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood int lastSlash = path.lastIndexOf('/'); 1872b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (lastSlash > 0) { 1873b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String parentPath = path.substring(0, lastSlash); 1874b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (parentPath.equals(Environment.getExternalStorageDirectory().getAbsolutePath())) { 1875b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood return 0; 1876b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1877b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String [] selargs = { parentPath }; 1878b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood Cursor c = db.query("objects", null, MediaStore.MediaColumns.DATA + "=?", 1879b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood selargs, null, null, null); 1880b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood try { 1881b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (c == null || c.getCount() == 0) { 1882b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // parent isn't in the database - so add it 1883b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood ContentValues values = new ContentValues(); 18841717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.FORMAT, Mtp.Object.FORMAT_ASSOCIATION); 18851717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.DATA, parentPath); 18861717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.PARENT, getParent(db, parentPath)); 1887d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood long parent = db.insert("objects", ObjectColumns.DATE_MODIFIED, values); 1888d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood sendObjectAdded(parent); 1889d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood return parent; 1890b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 1891b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood c.moveToFirst(); 1892b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood return c.getLong(0); 1893b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1894b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } finally { 1895b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (c != null) c.close(); 1896b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1897b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 1898b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood return 0; 1899b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1900b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1901b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 1902d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private long insertObject(SQLiteDatabase db, long objectHandle, ContentValues initialValues, 19035d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood int tableId, long rowId) { 1904b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String path = initialValues.getAsString(MediaStore.MediaColumns.DATA); 1905e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // path might be null for playlists created on the device 19065d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood 1907b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood ContentValues values = new ContentValues(); 19081717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.MEDIA_TABLE, tableId); 19091717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.MEDIA_ID, rowId); 1910b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 19115d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (objectHandle == 0) { 1912e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (path != null) { 1913e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood values.put(ObjectColumns.DATA, path); 1914e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 1915b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 19165d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood Long size = initialValues.getAsLong(MediaStore.MediaColumns.SIZE); 19175d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (size == null) { 1918e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (path != null) { 1919e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood File file = new File(path); 1920e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood values.put(ObjectColumns.SIZE, file.length()); 1921e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 19225d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } else { 19235d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood values.put(ObjectColumns.SIZE, size); 19245d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 1925b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 19265d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood Long parent = initialValues.getAsLong(ObjectColumns.PARENT); 19275d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (parent == null) { 1928e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (path != null) { 1929e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long parentId = getParent(db, path); 1930e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood values.put(ObjectColumns.PARENT, parentId); 1931e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 19325d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } else { 19335d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood values.put(ObjectColumns.PARENT, parent); 19345d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 1935b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 19365d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood Integer format = initialValues.getAsInteger(ObjectColumns.FORMAT); 19375d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (format == null) { 1938e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (path == null) { 1939e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // special case device created playlists 1940e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (tableId == AUDIO_PLAYLISTS) { 1941e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood values.put(ObjectColumns.FORMAT, Mtp.Object.FORMAT_ABSTRACT_AV_PLAYLIST); 1942e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // create a file path for the benefit of MTP 1943e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood path = Environment.getExternalStorageDirectory().getAbsolutePath() 1944e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood + "/Playlists/" + initialValues.getAsString(Audio.Playlists.NAME); 1945e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood values.put(MediaStore.MediaColumns.DATA, path); 1946e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood values.put(ObjectColumns.PARENT, getParent(db, path)); 1947e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } else { 1948e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood Log.e(TAG, "path is null in insertObject()"); 1949e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 1950e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } else { 1951e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood String mimeType = initialValues.getAsString(MediaStore.MediaColumns.MIME_TYPE); 1952e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood values.put(ObjectColumns.FORMAT, MediaFile.getFormatCode(path, mimeType)); 1953e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 19545d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } else { 19555d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood values.put(ObjectColumns.FORMAT, format); 19565d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 1957b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 19585d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood Integer modified = initialValues.getAsInteger(MediaStore.MediaColumns.DATE_MODIFIED); 19595d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (modified != null) { 19605d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood values.put(ObjectColumns.DATE_MODIFIED, modified); 19615d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 19625d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood 19635d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood objectHandle = db.insert("objects", ObjectColumns.DATE_MODIFIED, values); 1964d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (LOCAL_LOGV) Log.v(TAG, "insertObject: values=" + values + " returned: " + objectHandle); 19655d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } else { 19665d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood // only need to update MEDIA_TABLE and MEDIA_ID 19675d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood db.update("objects", values, ObjectColumns._ID + "=?", 19685d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood new String[] { Long.toString(objectHandle) }); 19695d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 1970d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood return objectHandle; 19711717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood } 19721717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 19735d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood private int deleteObject(SQLiteDatabase db, String volume, String table, 19745d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood String where, String[] whereArgs) { 1975e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // delete from corresponding media table as well 1976e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood Cursor c = db.query("objects", mMediaTableColumns, where, whereArgs, null, null, null); 1977e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 19785d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (c != null && c.moveToNext()) { 19795d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood int mediaTable = c.getInt(1); 19805d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood long mediaId = c.getLong(2); 19815d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (mediaId > 0) { 19825d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood // call back to our delete method rather than deleting directly 19835d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood // so notifications will be sent. 19845d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood switch (mediaTable) { 19855d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood case IMAGES_MEDIA: 19865d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood delete(ContentUris.withAppendedId( 19871717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Images.Media.getContentUri(volume), mediaId), null, null); 19885d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood break; 19895d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood case AUDIO_MEDIA: 19905d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood delete(ContentUris.withAppendedId( 19911717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Audio.Media.getContentUri(volume), mediaId), null, null); 19925d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood break; 19935d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood case VIDEO_MEDIA: 19945d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood delete(ContentUris.withAppendedId( 19951717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Video.Media.getContentUri(volume), mediaId), null, null); 19965d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood break; 19975d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood case AUDIO_PLAYLISTS: 19985d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood delete(ContentUris.withAppendedId( 19991717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Audio.Playlists.getContentUri(volume), mediaId), null, null); 20005d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood break; 20015d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood default: 20025d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood Log.e(TAG, "unknown mediaTable " + mediaTable + " in deleteObject()"); 20035d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood break; 20045d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 20051717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood } 20061717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood } 20075d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } finally { 20085d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (c != null) { 20095d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood c.close(); 20105d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 20111717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood } 20121717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood return db.delete("objects", where, whereArgs); 2013b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2014b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2015e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood private Cursor getObjectReferences(SQLiteDatabase db, int handle) { 2016e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood Cursor c = db.query("objects", mMediaTableColumns, "_id=?", 2017e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Integer.toString(handle) }, 2018e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 2019e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 2020e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 2021e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int mediaTable = c.getInt(1); 2022e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long mediaId = c.getLong(2); 2023e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (mediaTable != AUDIO_PLAYLISTS) { 2024e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only support object references for playlist objects 2025e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return null; 2026e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2027e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return db.rawQuery(OBJECT_REFERENCES_QUERY, 2028e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Long.toString(mediaId) } ); 2029e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2030e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 2031e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 2032e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 2033e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2034e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2035e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return null; 2036e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2037e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2038e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood private int setObjectReferences(SQLiteDatabase db, int handle, ContentValues values[]) { 2039e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // first look up the media table and media ID for the object 2040e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long playlistId = 0; 2041e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood Cursor c = db.query("objects", mMediaTableColumns, "_id=?", 2042e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Integer.toString(handle) }, 2043e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 2044e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 2045e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 2046e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int mediaTable = c.getInt(1); 2047e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (mediaTable != AUDIO_PLAYLISTS) { 2048e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only support object references for playlist objects 2049e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return 0; 2050e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2051e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood playlistId = c.getLong(2); 2052e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2053e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 2054e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 2055e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 2056e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2057e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2058e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (playlistId == 0) { 2059e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return 0; 2060e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2061e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2062e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // next delete any existing entries 2063e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood db.delete("audio_playlists_map", "playlist_id=?", 2064e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Long.toString(playlistId) }); 2065e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2066e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // finally add the new entries 2067e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int count = values.length; 2068e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int added = 0; 2069e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues[] valuesList = new ContentValues[count]; 2070e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood for (int i = 0; i < count; i++) { 2071e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // convert object ID to audio ID 2072e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long audioId = 0; 2073e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long objectId = values[i].getAsLong(MediaStore.MediaColumns._ID); 2074e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c = db.query("objects", mMediaTableColumns, "_id=?", 2075e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Long.toString(objectId) }, 2076e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 2077e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 2078e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 2079e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int mediaTable = c.getInt(1); 2080e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (mediaTable != AUDIO_MEDIA) { 2081e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only allow audio files in playlists, so skip 2082e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood continue; 2083e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2084e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood audioId = c.getLong(2); 2085e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2086e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 2087e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 2088e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 2089e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2090e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2091e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (audioId != 0) { 2092e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues v = new ContentValues(); 2093e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood v.put(MediaStore.Audio.Playlists.Members.PLAYLIST_ID, playlistId); 2094e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood v.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audioId); 2095e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood v.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, added++); 2096e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood valuesList[i] = v; 2097e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2098e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2099e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (added < count) { 2100e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we weren't able to find everything on the list, so lets resize the array 2101e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // and pass what we have. 2102e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues[] newValues = new ContentValues[added]; 2103e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood System.arraycopy(valuesList, 0, newValues, 0, added); 2104e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood valuesList = newValues; 2105e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2106e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return playlistBulkInsert(db, 2107e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood Audio.Playlists.Members.getContentUri(EXTERNAL_VOLUME, playlistId), 2108e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood valuesList); 2109e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2110e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 21115d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood private Uri insertInternal(Uri uri, int match, ContentValues initialValues) { 2112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 21135d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood int objectHandle = 0; 2114d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood String mediaTable = null; 2115702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2116d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (LOCAL_LOGV) Log.v(TAG, "insertInternal: "+uri+", initValues="+initialValues); 2117702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 2118702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 2119702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mMediaScannerVolume = initialValues.getAsString(MediaStore.MEDIA_SCANNER_VOLUME); 2120702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return MediaStore.getMediaScannerUri(); 2121702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2122702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2123702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri newUri = null; 2124702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 2125702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null && match != VOLUMES) { 2126702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2127702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 2128702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2129702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = (match == VOLUMES ? null : database.getWritableDatabase()); 2130702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2131702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (initialValues == null) { 2132702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project initialValues = new ContentValues(); 21335d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } else { 2134d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Integer i = initialValues.getAsInteger( 2135d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID); 21365d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (i != null) { 21375d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood objectHandle = i.intValue(); 2138d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood initialValues.remove(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID); 21395d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 2140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2141702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2142702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 2143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: { 2144702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", "DCIM/Camera"); 2145702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2146702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 2147702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString(MediaColumns.DATA); 2148702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (! values.containsKey(MediaColumns.DISPLAY_NAME)) { 2149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 2150702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 2152b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen computeTakenTime(values); 2153d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mediaTable = "images"; 2154d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood rowId = db.insert(mediaTable, "name", values); 2155702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId( 2158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Images.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 21599299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen requestMediaThumbnail(data, newUri, MediaThumbRequest.PRIORITY_NORMAL, 0); 2160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2163702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2164b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This will be triggered by requestMediaThumbnail (see getThumbnailUri) 2165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: { 2166b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", 2167b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 2168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("thumbnails", "name", values); 2169702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Images.Thumbnails. 2171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContentUri(uri.getPathSegments().get(0)), rowId); 2172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2175702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2176b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This is currently only used by MICRO_KIND video thumbnail (see getThumbnailUri) 2177b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: { 2178b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", 2179b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 2180b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen rowId = db.insert("videothumbnails", "name", values); 2181b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (rowId > 0) { 2182b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Thumbnails. 2183b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen getContentUri(uri.getPathSegments().get(0)), rowId); 2184b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2185b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 2186b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2187b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2188702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: { 2189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // SQLite Views are read-only, so we need to deconstruct this 2190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // insert and do inserts into the underlying tables. 2191702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If doing this here turns out to be a performance bottleneck, 2192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // consider moving this to native code and using triggers on 2193702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the view. 2194702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2195702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2196acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // TODO Remove this and actually store the album_artist in the 2197acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // database. For now this is here so the media scanner can start 2198acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // sending us the album_artist, even though it's not in the db yet. 2199acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen values.remove(MediaStore.Audio.Media.ALBUM_ARTIST); 2200acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 2201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Insert the artist into the artist table and remove it from 2202702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the input values 2203702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Object so = values.get("artist"); 2204702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = (so == null ? "" : so.toString()); 2205702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("artist"); 2206702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long artistRowId; 2207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> artistCache = database.mArtistCache; 220859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String path = values.getAsString("_data"); 2209702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(artistCache) { 2210702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long temp = artistCache.get(s); 2211702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 2212702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = getKeyIdForName(db, "artists", "artist_key", "artist", 2213a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, s, path, 0, null, artistCache, uri); 2214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = temp.longValue(); 2216702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2217702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2218a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist = s; 2219702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2220702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Do the same for the album field 2221702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.get("album"); 2222702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = (so == null ? "" : so.toString()); 2223702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("album"); 2224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long albumRowId; 2225702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> albumCache = database.mAlbumCache; 2226702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(albumCache) { 222759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen int albumhash = path.substring(0, path.lastIndexOf('/')).hashCode(); 222859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String cacheName = s + albumhash; 222959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Long temp = albumCache.get(cacheName); 2230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 2231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = getKeyIdForName(db, "albums", "album_key", "album", 2232a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, cacheName, path, albumhash, artist, albumCache, uri); 2233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2234702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = temp; 2235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2237702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2238702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("artist_id", Integer.toString((int)artistRowId)); 2239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("album_id", Integer.toString((int)albumRowId)); 2240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.getAsString("title"); 2241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = (so == null ? "" : so.toString()); 2242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("title_key", MediaStore.Audio.keyFor(s)); 2243358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen // do a final trim of the title, in case it started with the special 2244358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen // "sort first" character (ascii \001) 2245358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen values.remove("title"); 2246358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen values.put("title", s.trim()); 2247702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2248702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(values.getAsString("_data"), values); 2249702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 2250702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2251d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mediaTable = "audio_meta"; 2252d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood rowId = db.insert(mediaTable, "duration", values); 2253702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2254702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 2255702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: { 2260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 2261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.AUDIO_ID, audioId); 2263ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_genres_map", "genre_id", values); 2264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2267702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2270702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: { 2271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 2272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.AUDIO_ID, audioId); 2274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_playlists_map", "playlist_id", 2275702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values); 2276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2277702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2278702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2279702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2280702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2281702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: { 2283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_genres", "audio_id", initialValues); 2284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Genres.getContentUri(uri.getPathSegments().get(0)), rowId); 2286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2287702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2288702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2290702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: { 2291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long genreId = Long.parseLong(uri.getPathSegments().get(3)); 2292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.GENRE_ID, genreId); 2294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_genres_map", "genre_id", values); 2295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2296702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2299702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2300702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: { 2302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.Audio.Playlists.DATE_ADDED, System.currentTimeMillis() / 1000); 2304d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mediaTable = "audio_playlists"; 2305d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood rowId = db.insert(mediaTable, "name", initialValues); 2306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2307702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Playlists.getContentUri(uri.getPathSegments().get(0)), rowId); 2308702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2309702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2310702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2311702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2312702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: { 2314702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 2315702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2316702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.PLAYLIST_ID, playlistId); 2317ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_playlists_map", "playlist_id", values); 2318702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2319702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2320702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2321702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2324702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: { 2325702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = ensureFile(database.mInternal, initialValues, ".3gp", "video"); 2326702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString("_data"); 2327702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 2328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 2329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 2330498b62c2912302a23532c73a028a7684c5df33caRay Chen computeTakenTime(values); 2331d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mediaTable = "video"; 2332d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood rowId = db.insert(mediaTable, "artist", values); 2333702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2334b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Media.getContentUri( 2335b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen uri.getPathSegments().get(0)), rowId); 23369299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen requestMediaThumbnail(data, newUri, MediaThumbRequest.PRIORITY_NORMAL, 0); 2337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART: 2342702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database.mInternal) { 2343702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("no internal album art allowed"); 2344702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = null; 2346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 2348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IllegalStateException ex) { 2349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // probably no more room to store albumthumbs 2350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = initialValues; 2351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("album_art", "_data", values); 2353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VOLUMES: 2359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return attachVolume(initialValues.getAsString("name")); 2360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 23615d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood case MTP_OBJECTS: { 2362abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood try { 2363abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood mDisableMtpObjectCallbacks = true; 2364d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood rowId = db.insert("objects", ObjectColumns.DATE_MODIFIED, initialValues); 2365abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood if (rowId > 0) { 2366abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood newUri = MtpObjects.getContentUri(uri.getPathSegments().get(0), rowId); 2367abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood } 2368abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood } finally { 2369abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood mDisableMtpObjectCallbacks = false; 23705d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 23715d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood break; 23725d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 23735d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood 2374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Invalid URI " + uri); 2376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2378abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood // don't bother populating internal objects database since we are not sharing it via MTP 2379abf5daf6a8c2f9441af98b489398a476e7c6564cMike Lockwood if (rowId > 0 && mediaTable != null && !database.mInternal) { 2380d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood long objectId = insertObject(db, objectHandle, initialValues, match, rowId); 2381d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 2382d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // Set object_id in the media table 2383d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood ContentValues values = new ContentValues(); 2384d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood values.put(MediaColumns.MTP_OBJECT_ID, objectId); 2385d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood db.update(mediaTable, values, MediaColumns._ID + "=?", 2386d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood new String[] { Long.toString(rowId) }); 2387d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 2388d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood sendObjectAdded(objectId); 2389b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2390b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 2392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2394cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen @Override 2395cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 2396cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen throws OperationApplicationException { 2397cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 2398cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // The operations array provides no overall information about the URI(s) being operated 2399cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // on, so begin a transaction for ALL of the databases. 2400cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ihelper = getDatabaseForUri(MediaStore.Audio.Media.INTERNAL_CONTENT_URI); 2401cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ehelper = getDatabaseForUri(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI); 2402cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase idb = ihelper.getWritableDatabase(); 2403cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.beginTransaction(); 2404cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase edb = null; 2405cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (ehelper != null) { 2406cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb = ehelper.getWritableDatabase(); 2407cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.beginTransaction(); 2408cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2409cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen try { 2410cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentProviderResult[] result = super.applyBatch(operations); 2411cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.setTransactionSuccessful(); 2412cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 2413cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.setTransactionSuccessful(); 2414cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2415cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // Rather than sending targeted change notifications for every Uri 2416cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // affected by the batch operation, just invalidate the entire internal 2417cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // and external name space. 2418cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentResolver res = getContext().getContentResolver(); 2419cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen res.notifyChange(Uri.parse("content://media/"), null); 2420cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen return result; 2421cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } finally { 2422cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.endTransaction(); 2423cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 2424cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.endTransaction(); 2425cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2426cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2427cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2428cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 2429cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 24309299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen private MediaThumbRequest requestMediaThumbnail(String path, Uri uri, int priority, long magic) { 2431b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 2432e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen MediaThumbRequest req = null; 2433e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen try { 2434e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen req = new MediaThumbRequest( 24359299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen getContext().getContentResolver(), path, uri, priority, magic); 2436e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen mMediaThumbQueue.add(req); 2437e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen // Trigger the handler. 2438e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Message msg = mThumbHandler.obtainMessage(IMAGE_THUMB); 2439e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen msg.sendToTarget(); 2440e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } catch (Throwable t) { 2441e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Log.w(TAG, t); 2442e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 2443b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return req; 2444b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2445b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2446b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String generateFileName(boolean internal, String preferredExtension, String directoryName) 2448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a random file 2450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = String.valueOf(System.currentTimeMillis()); 2451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (internal) { 2453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Writing to internal storage is not supported."); 2454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// return Environment.getDataDirectory() 2455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// + "/" + directoryName + "/" + name + preferredExtension; 2456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Environment.getExternalStorageDirectory() 2458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project + "/" + directoryName + "/" + name + preferredExtension; 2459702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2460702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private boolean ensureFileExists(String path) { 2463702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(path); 2464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.exists()) { 2465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 2466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we will not attempt to create the first directory in the path 2468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // (for example, do not create /sdcard if the SD card is not mounted) 2469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int secondSlash = path.indexOf('/', 1); 2470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (secondSlash < 1) return false; 2471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String directoryPath = path.substring(0, secondSlash); 2472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File directory = new File(directoryPath); 2473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!directory.exists()) 2474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 2475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.getParentFile().mkdirs(); 2476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return file.createNewFile(); 2478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch(IOException ioe) { 2479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "File creation failed", ioe); 2480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 2482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final class GetTableAndWhereOutParameter { 2486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String table; 2487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String where; 2488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final GetTableAndWhereOutParameter sGetTableAndWhereParam = 2491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new GetTableAndWhereOutParameter(); 2492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void getTableAndWhere(Uri uri, int match, String userWhere, 2494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project GetTableAndWhereOutParameter out) { 2495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String where = null; 2496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 24979f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin case IMAGES_MEDIA: 24989f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin out.table = "images"; 24999f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin break; 25009f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin 2501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 2502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "images"; 2503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id = " + uri.getPathSegments().get(3); 2504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2506b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS_ID: 2507b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 2508b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 2509b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "thumbnails"; 2510b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 2511b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio"; 2514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio"; 2518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 2522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 2524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 2527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 2529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND genre_id=" + uri.getPathSegments().get(5); 2530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 2533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 2535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 2538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 2540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND playlists_id=" + uri.getPathSegments().get(5); 2541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 2544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 2548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 2553702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2554702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "genre_id=" + uri.getPathSegments().get(3); 2555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2557702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 2558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "genre_id=" + uri.getPathSegments().get(3) + 2560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND audio_id =" + uri.getPathSegments().get(5); 2561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 2564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 2573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 2574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3); 2575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 2579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3) + 2580702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _id=" + uri.getPathSegments().get(5); 2581702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 2584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "album_art"; 2585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "album_id=" + uri.getPathSegments().get(3); 2586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2588702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2589702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "video"; 2590702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "video"; 2594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2597b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 2598b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 2599b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 2600b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "videothumbnails"; 2601b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 2602b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 26031717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood case MTP_OBJECTS_ID: 26041717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood where = "_id=" + uri.getPathSegments().get(2); 26051717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood case MTP_OBJECTS: 26061717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood out.table = "objects"; 26071717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood break; 26081717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 2609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown or unsupported URL: " + uri.toString()); 2612702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Add in the user requested WHERE clause, if needed 2615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(userWhere)) { 2616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(where)) { 2617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where + " AND (" + userWhere + ")"; 2618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = userWhere; 2620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where; 2623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int delete(Uri uri, String userWhere, String[] whereArgs) { 2628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 2629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 2630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2631702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 2632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 2633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 2634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 0; 2635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mMediaScannerVolume = null; 2637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 1; 2638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match != VOLUMES_ID) { 2641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 2642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 2643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 2645702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2646702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 2647702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 2649702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 2650702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 2651702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2652702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2653702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.delete("audio_meta", 2654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 2655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 26561717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood case MTP_OBJECTS: 26571717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood throw new UnsupportedOperationException( 26581717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood "Deleting multiple objects via MTP not supported"); 26591717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood case MTP_OBJECTS_ID: 2660d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood try { 2661d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // don't send objectRemoved event since this originated from MTP 2662d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mDisableMtpObjectCallbacks = true; 2663d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // return here to avoid calling notifyChange() 2664d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood return deleteObject(db, uri.getPathSegments().get(0), 2665d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood sGetTableAndWhereParam.table, 2666d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood sGetTableAndWhereParam.where, whereArgs); 2667d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } finally { 2668d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mDisableMtpObjectCallbacks = false; 2669d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.delete(sGetTableAndWhereParam.table, 2672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 2673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project detachVolume(uri); 2679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = 1; 2680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 2683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int update(Uri uri, ContentValues initialValues, String userWhere, 2687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] whereArgs) { 2688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 2689b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // Log.v(TAG, "update for uri="+uri+", initValues="+initialValues); 2690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 2691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 2692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 2693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2694702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 2695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 2697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 2699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 2700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 2702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2706acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // TODO Remove this and actually store the album_artist in the 2707acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // database. For now this is here so the media scanner can start 2708acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // sending us the album_artist, even though it's not in the db yet. 2709acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen values.remove(MediaStore.Audio.Media.ALBUM_ARTIST); 271007656cccafca173c6ab54c681a69538dcf0516ddMarco Nelissen 2711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Insert the artist into the artist table and remove it from 2712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the input values 2713a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist = values.getAsString("artist"); 27146006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("artist"); 2715a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (artist != null) { 2716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long artistRowId; 2717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> artistCache = database.mArtistCache; 2718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(artistCache) { 2719a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen Long temp = artistCache.get(artist); 2720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 2721acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen artistRowId = getKeyIdForName(db, "artists", "artist_key", "artist", 2722acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen artist, artist, null, 0, null, artistCache, uri); 2723702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = temp.longValue(); 2725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("artist_id", Integer.toString((int)artistRowId)); 2728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 273059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Do the same for the album field. 2731a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String so = values.getAsString("album"); 27326006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("album"); 2733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 273459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String path = values.getAsString("_data"); 273559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen int albumHash = 0; 273659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (path == null) { 273759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // If the path is null, we don't have a hash for the file in question. 273859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Log.w(TAG, "Update without specified path."); 273959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } else { 274059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen albumHash = path.substring(0, path.lastIndexOf('/')).hashCode(); 274159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 2742702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 2743702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long albumRowId; 2744702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> albumCache = database.mAlbumCache; 2745702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(albumCache) { 274659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String cacheName = s + albumHash; 274759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Long temp = albumCache.get(cacheName); 2748702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 2749702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = getKeyIdForName(db, "albums", "album_key", "album", 2750a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, cacheName, path, albumHash, artist, albumCache, uri); 2751702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = temp.longValue(); 2753702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2754702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2755702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("album_id", Integer.toString((int)albumRowId)); 2756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2757702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2758702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // don't allow the title_key field to be updated directly 2759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("title_key"); 2760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the title field is modified, update the title_key 2761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.getAsString("title"); 2762702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 2763702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 2764702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("title_key", MediaStore.Audio.keyFor(s)); 2765e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // do a final trim of the title, in case it started with the special 2766e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // "sort first" character (ascii \001) 2767e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.remove("title"); 2768e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.put("title", s.trim()); 2769702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update("audio_meta", values, sGetTableAndWhereParam.where, 2772702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project whereArgs); 2773702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2774702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2775702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 2776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 2777702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2779702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2780702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Don't allow bucket id or display name to be updated directly. 2782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // The same names are used for both images and table columns, so 2783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we use the ImageColumns constants here. 2784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_ID); 2785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_DISPLAY_NAME); 2786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the data is being modified update the bucket values 2787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString(MediaColumns.DATA); 2788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (data != null) { 2789702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 2790702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2791b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen computeTakenTime(values); 2792702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, values, 2793702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 279401a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // if this is a request from MediaScanner, DATA should contains file path 279501a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // we only process update request from media scanner, otherwise the requests 279601a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // could be duplicate. 279701a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen if (count > 0 && values.getAsString(MediaStore.MediaColumns.DATA) != null) { 279801a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen Cursor c = db.query(sGetTableAndWhereParam.table, 279901a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen READY_FLAG_PROJECTION, sGetTableAndWhereParam.where, 280001a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen whereArgs, null, null, null); 2801b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c != null) { 2802216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen try { 2803216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen while (c.moveToNext()) { 2804216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen long magic = c.getLong(2); 2805216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (magic == 0) { 2806216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen requestMediaThumbnail(c.getString(1), uri, 2807216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen MediaThumbRequest.PRIORITY_NORMAL, 0); 2808216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 2809b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2810216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } finally { 2811216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c.close(); 2812b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2813b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2814b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2817f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 2818f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2819f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String moveit = uri.getQueryParameter("move"); 2820f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (moveit != null) { 2821f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String key = MediaStore.Audio.Playlists.Members.PLAY_ORDER; 2822f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (initialValues.containsKey(key)) { 2823f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int newpos = initialValues.getAsInteger(key); 2824f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen List <String> segments = uri.getPathSegments(); 2825f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen long playlist = Long.valueOf(segments.get(3)); 2826f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int oldpos = Integer.valueOf(segments.get(5)); 2827f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return movePlaylistEntry(db, playlist, oldpos, newpos); 2828f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2829f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen throw new IllegalArgumentException("Need to specify " + key + 2830f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " when using 'move' parameter"); 2831f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2832f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // fall through 2833702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2834702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, initialValues, 2835702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 2836702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2837702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2838702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2839cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // in a transaction, the code that began the transaction should be taking 2840cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // care of notifications once it ends the transaction successfully 2841cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (count > 0 && !db.inTransaction()) { 2842702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2843702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2844702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 2845702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2846702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2847f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen private int movePlaylistEntry(SQLiteDatabase db, long playlist, int from, int to) { 2848f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from == to) { 2849f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return 0; 2850f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2851f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.beginTransaction(); 2852f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen try { 2853f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int numlines = 0; 2854f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=-1" + 2855f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order=" + from + 2856f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 2857f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // We could just run both of the next two statements, but only one of 2858f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // of them will actually do anything, so might as well skip the compile 2859f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // and execute steps. 2860f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from < to) { 2861f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order-1" + 2862f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order<=" + to + " AND play_order>" + from + 2863f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 2864f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = to - from + 1; 2865f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } else { 2866f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order+1" + 2867f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order>=" + to + " AND play_order<" + from + 2868f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 2869f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = from - to + 1; 2870f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2871f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=" + to + 2872f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order=-1 AND playlist_id=" + playlist); 2873f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.setTransactionSuccessful(); 2874f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen Uri uri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI 2875f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen .buildUpon().appendEncodedPath(String.valueOf(playlist)).build(); 2876f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 2877f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return numlines; 2878f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } finally { 2879f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.endTransaction(); 2880f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2881f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2882f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 2883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] openFileColumns = new String[] { 2884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.DATA, 2885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 2886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public ParcelFileDescriptor openFile(Uri uri, String mode) 2889702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throws FileNotFoundException { 289071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 2891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = null; 289271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 289371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_FILE_ID) { 289471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // get album art for the specified media file 289571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen DatabaseHelper database = getDatabaseForUri(uri); 289671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (database == null) { 289771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw new IllegalStateException("Couldn't open database for " + uri); 289871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 289971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteDatabase db = database.getReadableDatabase(); 290071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 290171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int songid = Integer.parseInt(uri.getPathSegments().get(3)); 290271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 290371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.appendWhere("_id=" + songid); 290471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Cursor c = qb.query(db, 290571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen new String [] { 290671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.DATA, 290771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.ALBUM_ID }, 290871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen null, null, null, null, null); 290971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 291071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen String audiopath = c.getString(0); 291171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int albumid = c.getInt(1); 291271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // Try to get existing album art for this album first, which 291371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // could possibly have been obtained from a different file. 291471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // If that fails, try to get it from this specific file. 291571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri newUri = ContentUris.withAppendedId(ALBUMART_URI, albumid); 291671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 291771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = openFile(newUri, mode); // recursive call 291871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (FileNotFoundException ex) { 291971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // That didn't work, now try to get it from the specific file 292071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, null); 292171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 292271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 292371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen c.close(); 292471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return pfd; 292571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 292671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 2927702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2928702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd = openFileHelper(uri, mode); 2929702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (FileNotFoundException ex) { 293071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (mode.contains("w")) { 293171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // if the file couldn't be created, we shouldn't extract album art 293271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 293371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 293471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 2935702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_ID) { 2936702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Tried to open an album art file which does not exist. Regenerate. 2937702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 2938702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 2939702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw ex; 2940702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2941702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getReadableDatabase(); 2942702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 2943702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int albumid = Integer.parseInt(uri.getPathSegments().get(3)); 294471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 2945702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("album_id=" + albumid); 2946702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, 2947702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String [] { 2948702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Media.DATA }, 2949702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project null, null, null, null, null); 295071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 2951702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String audiopath = c.getString(0); 295271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, uri); 2953702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2954702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.close(); 2955702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 295671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (pfd == null) { 295771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 295871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 2959702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2960702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return pfd; 2961702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2962702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2963702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private class ThumbData { 2964702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db; 2965702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path; 2966702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long album_id; 2967702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri albumart_uri; 2968702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2969702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2970a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen private void makeThumbAsync(SQLiteDatabase db, String path, long album_id) { 29718a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mPendingThumbs) { 29728a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (mPendingThumbs.contains(path)) { 29738a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // There's already a request to make an album art thumbnail 29748a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // for this audio file in the queue. 29758a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return; 29768a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 29778a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 29788a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mPendingThumbs.add(path); 29798a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 29808a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 2981702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ThumbData d = new ThumbData(); 2982702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.db = db; 2983702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.path = path; 2984702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.album_id = album_id; 2985a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen d.albumart_uri = ContentUris.withAppendedId(mAlbumArtBaseUri, album_id); 29868a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 29878a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Instead of processing thumbnail requests in the order they were 29888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // received we instead process them stack-based, i.e. LIFO. 29898a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The idea behind this is that the most recently requested thumbnails 29908a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // are most likely the ones still in the user's view, whereas those 29918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // requested earlier may have already scrolled off. 29928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mThumbRequestStack) { 29938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mThumbRequestStack.push(d); 29948a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 29958a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 29968a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Trigger the handler. 2997b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Message msg = mThumbHandler.obtainMessage(ALBUM_THUMB); 2998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project msg.sendToTarget(); 2999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 30018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Extract compressed image data from the audio file itself or, if that fails, 30028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // look for a file "AlbumArt.jpg" in the containing directory. 30038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private static byte[] getCompressedAlbumArt(Context context, String path) { 30048a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = null; 3005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3007702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File f = new File(path); 3008702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, 3009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor.MODE_READ_ONLY); 3010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 30118a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber MediaScanner scanner = new MediaScanner(context); 30128a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber compressed = scanner.extractAlbumArt(pfd.getFileDescriptor()); 3013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd.close(); 3014702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3015d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // If no embedded art exists, look for a suitable image file in the 30163f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // same directory as the media file, except if that directory is 30173f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // is the root directory of the sd card or the download directory. 3018d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // We look for, in order of preference: 3019d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 0 AlbumArt.jpg 3020d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 1 AlbumArt*Large.jpg 3021d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 2 Any other jpg image with 'albumart' anywhere in the name 3022d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 3 Any other jpg image 3023d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 4 any other png image 30248a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null && path != null) { 3025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lastSlash = path.lastIndexOf('/'); 3026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lastSlash > 0) { 3027d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 30283f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen String artPath = path.substring(0, lastSlash); 30293f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen String sdroot = Environment.getExternalStorageDirectory().getAbsolutePath(); 30300fe3097230b324e65a874bd7c8c0f430d2fb8cbeMarco Nelissen String dwndir = Environment.getExternalStoragePublicDirectory( 30312f07f572bc574b685b491ee07a6209c7f2dcb13fMarco Nelissen Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(); 3032d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 3033d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String bestmatch = null; 3034d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen synchronized (sFolderArtMap) { 3035d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (sFolderArtMap.containsKey(artPath)) { 3036d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = sFolderArtMap.get(artPath); 3037ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } else if (!artPath.equalsIgnoreCase(sdroot) && 3038ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen !artPath.equalsIgnoreCase(dwndir)) { 3039d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen File dir = new File(artPath); 3040d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String [] entrynames = dir.list(); 3041d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entrynames == null) { 3042d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen return null; 3043d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 3044d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = null; 3045d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen int matchlevel = 1000; 3046d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen for (int i = entrynames.length - 1; i >=0; i--) { 3047d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String entry = entrynames[i].toLowerCase(); 3048d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entry.equals("albumart.jpg")) { 3049d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3050d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen break; 3051d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.startsWith("albumart") 3052d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith("large.jpg") 3053d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 1) { 3054d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3055d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 1; 3056d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.contains("albumart") 3057d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith(".jpg") 3058d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 2) { 3059d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3060d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 2; 3061d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".jpg") && matchlevel > 3) { 3062d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3063d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 3; 3064d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".png") && matchlevel > 4) { 3065d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3066d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 4; 3067d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 3068d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 3069d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // note that this may insert null if no album art was found 3070d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen sFolderArtMap.put(artPath, bestmatch); 3071d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 3072d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 3073d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 3074d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (bestmatch != null) { 30753f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen File file = new File(artPath, bestmatch); 3076d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (file.exists()) { 3077d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = new byte[(int)file.length()]; 3078d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen FileInputStream stream = null; 3079d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen try { 3080d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream = new FileInputStream(file); 3081d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.read(compressed); 3082d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } catch (IOException ex) { 3083d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = null; 3084d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } finally { 3085d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (stream != null) { 3086d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.close(); 3087d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 3088702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3089702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 30938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IOException e) { 30948a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 3095702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 30968a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return compressed; 30978a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 3098702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 30998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Return a URI to write the album art to and update the database as necessary. 31008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Uri getAlbumArtOutputUri(SQLiteDatabase db, long album_id, Uri albumart_uri) { 31018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Uri out = null; 31028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // TODO: this could be done more efficiently with a call to db.replace(), which 31038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // replaces or inserts as needed, making it unnecessary to query() first. 31048a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (albumart_uri != null) { 31058a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Cursor c = query(albumart_uri, new String [] { "_data" }, 31068a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber null, null, null); 310771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 31088a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber String albumart_path = c.getString(0); 31098a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (ensureFileExists(albumart_path)) { 31108a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber out = albumart_uri; 3111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 311271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } else { 311371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen albumart_uri = null; 3114702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 31158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber c.close(); 311671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 311771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (albumart_uri == null){ 31188a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues initialValues = new ContentValues(); 31198a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber initialValues.put("album_id", album_id); 31208a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 31218a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 31228a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber long rowId = db.insert("album_art", "_data", values); 31238a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (rowId > 0) { 31248a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber out = ContentUris.withAppendedId(ALBUMART_URI, rowId); 3125702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 31268a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IllegalStateException ex) { 31278a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating album thumb file"); 31288a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 31298a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 31308a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return out; 31318a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 31328a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 31338a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Write out the album art to the output URI, recompresses the given Bitmap 31348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // if necessary, otherwise writes the compressed data. 31358a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private void writeAlbumArt( 31368a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress, Uri out, byte[] compressed, Bitmap bm) { 31378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean success = false; 31388a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 31398a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber OutputStream outstream = getContext().getContentResolver().openOutputStream(out); 31408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 31418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!need_to_recompress) { 31428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // No need to recompress here, just write out the original 31438a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // compressed data here. 31448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.write(compressed); 31458a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber success = true; 31468a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 31478a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber success = bm.compress(Bitmap.CompressFormat.JPEG, 75, outstream); 3148702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 31498a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 31508a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.close(); 31518a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (FileNotFoundException ex) { 31528a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 3153702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IOException ex) { 31548a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 31558a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 31568a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!success) { 31578a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // the thumbnail was not written successfully, delete the entry that refers to it 31588a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber getContext().getContentResolver().delete(out, null, null); 3159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 31608a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 31618a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 316271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor getThumb(SQLiteDatabase db, String path, long album_id, 316371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri albumart_uri) { 316471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen ThumbData d = new ThumbData(); 316571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.db = db; 316671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.path = path; 316771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.album_id = album_id; 316871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.albumart_uri = albumart_uri; 316971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return makeThumbInternal(d); 317071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 317171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 317271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor makeThumbInternal(ThumbData d) { 31738a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = getCompressedAlbumArt(getContext(), d.path); 3174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 31758a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null) { 317671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 31778a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 31788a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 31798a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Bitmap bm = null; 31808a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress = true; 31818a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 31828a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 31838a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the size of the bitmap 31848a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.Options opts = new BitmapFactory.Options(); 31858a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = true; 31868a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize = 1; 31878a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 31888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 31898a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // request a reasonably sized output image 31908a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // TODO: don't hardcode the size 31918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber while (opts.outHeight > 320 || opts.outWidth > 320) { 31928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outHeight /= 2; 31938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outWidth /= 2; 31948a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize *= 2; 31958a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 31968a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 31978a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (opts.inSampleSize == 1) { 31988a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The original album art was of proper size, we won't have to 31998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // recompress the bitmap later. 32008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber need_to_recompress = false; 32018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 32028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the image for real now 32038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = false; 32048a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inPreferredConfig = Bitmap.Config.RGB_565; 32058a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber bm = BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 32068a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 32078a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (bm != null && bm.getConfig() == null) { 3208a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen Bitmap nbm = bm.copy(Bitmap.Config.RGB_565, false); 3209a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (nbm != null && nbm != bm) { 3210a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 3211a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm = nbm; 3212a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 32138a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 32148a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 32158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (Exception e) { 32168a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 32178a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 32188a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (need_to_recompress && bm == null) { 321971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 32208a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 32218a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 322271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (d.albumart_uri == null) { 322371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // this one doesn't need to be saved (probably a song with an unknown album), 322471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // so stick it in a memory file and return that 322571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 322624001394f571b1f0378840cbf299288e4df10508Bjorn Bringert return ParcelFileDescriptor.fromData(compressed, "albumthumb"); 322771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (IOException e) { 322871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 322971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } else { 3230a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This one needs to actually be saved on the sd card. 3231a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This is wrapped in a transaction because there are various things 3232a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // that could go wrong while generating the thumbnail, and we only want 3233a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // to update the database when all steps succeeded. 3234a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.beginTransaction(); 3235a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen try { 3236a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen Uri out = getAlbumArtOutputUri(d.db, d.album_id, d.albumart_uri); 3237a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen 3238a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (out != null) { 3239a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen writeAlbumArt(need_to_recompress, out, compressed, bm); 3240a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen getContext().getContentResolver().notifyChange(MEDIA_URI, null); 3241a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen ParcelFileDescriptor pfd = openFileHelper(out, "r"); 3242a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.setTransactionSuccessful(); 3243a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen return pfd; 3244a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 3245a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (FileNotFoundException ex) { 3246a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 3247a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (UnsupportedOperationException ex) { 3248a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 3249a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } finally { 3250a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.endTransaction(); 3251a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (bm != null) { 3252a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 325371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 325471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 32558a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 325671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 3257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Look up the artist or album entry for the given name, creating that entry 3261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * if it does not already exists. 3262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db The database 3263702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param table The table to store the key/name pair in. 3264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param keyField The name of the key-column 3265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param nameField The name of the name-column 3266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param rawName The name that the calling app was trying to insert into the database 326759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param cacheName The string that will be inserted in to the cache 326859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param path The full path to the file being inserted in to the audio table 326959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param albumHash A hash to distinguish between different albums of the same name 3270a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen * @param artist The name of the artist, if known 3271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param cache The cache to add this entry to 3272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param srcuri The Uri that prompted the call to this method, used for determining whether this is 3273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * the internal or external database 3274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The row ID for this artist/album, or -1 if the provided name was invalid 3275702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private long getKeyIdForName(SQLiteDatabase db, String table, String keyField, String nameField, 327759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String rawName, String cacheName, String path, int albumHash, 3278a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist, HashMap<String, Long> cache, Uri srcuri) { 3279702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 3280702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3281702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rawName == null || rawName.length() == 0) { 3282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return -1; 3283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String k = MediaStore.Audio.keyFor(rawName); 3285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (k == null) { 3287702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return -1; 3288702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 329059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen boolean isAlbum = table.equals("albums"); 3291e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen boolean isUnknown = MediaStore.UNKNOWN_STRING.equals(rawName); 329259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 329359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // To distinguish same-named albums, we append a hash of the path. 329459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Ideally we would also take things like CDDB ID in to account, so 329559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // we can group files from the same album that aren't in the same 329659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // folder, but this is a quick and easy start that works immediately 329759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // without requiring support from the mp3, mp4 and Ogg meta data 329859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // readers, as long as the albums are in different folders. 3299a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isAlbum) { 330059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen k = k + albumHash; 3301a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isUnknown) { 3302a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen k = k + artist; 3303a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen } 330459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 330559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 3306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] selargs = { k }; 3307702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = db.query(table, null, keyField + "=?", selargs, null, null, null); 3308702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3309702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3310702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (c.getCount()) { 3311702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 0: { 3312702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // insert new entry into table 3313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues otherValues = new ContentValues(); 3314702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(keyField, k); 3315702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(nameField, rawName); 3316702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert(table, "duration", otherValues); 331759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (path != null && isAlbum && ! isUnknown) { 3318702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We just inserted a new album. Now create an album art thumbnail for it. 3319a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen makeThumbAsync(db, path, rowId); 3320702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3321702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 3323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 3324702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 3325702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3326702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3327702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 1: { 3329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Use the existing entry 3330702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.moveToFirst(); 3331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = c.getLong(0); 3332702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3333702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Determine whether the current rawName is better than what's 3334702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // currently stored in the table, and update the table if it is. 3335702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String currentFancyName = c.getString(2); 3336702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String bestName = makeBestName(rawName, currentFancyName); 3337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!bestName.equals(currentFancyName)) { 3338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // update the table with the new name 3339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues newValues = new ContentValues(); 3340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newValues.put(nameField, bestName); 3341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(table, newValues, "rowid="+Integer.toString((int)rowId), null); 3342702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 3343702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 3344702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 3345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 3349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // corrupt database 3350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Multiple entries in table " + table + " for key " + k); 3351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = -1; 3352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 3355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) c.close(); 3356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 335859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (cache != null && ! isUnknown) { 335959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen cache.put(cacheName, rowId); 3360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return rowId; 3362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Returns the best string to use for display, given two names. 3366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Note that this function does not necessarily return either one 3367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * of the provided names; it may decide to return a better alternative 3368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * (for example, specifying the inputs "Police" and "Police, The" will 3369702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * return "The Police") 3370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * The basic assumptions are: 3372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - longer is better ("The police" is better than "Police") 3373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - prefix is better ("The Police" is better than "Police, The") 3374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - accents are better ("Motörhead" is better than "Motorhead") 3375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param one The first of the two names to consider 3377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param two The last of the two names to consider 3378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The actual name to use 3379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String makeBestName(String one, String two) { 3381702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name; 3382702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Longer names are usually better. 3384702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.length() > two.length()) { 3385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 3386702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3387702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Names with accents are usually better, and conveniently sort later 3388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.toLowerCase().compareTo(two.toLowerCase()) > 0) { 3389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 3390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = two; 3392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Prefixes are better than postfixes. 3396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (name.endsWith(", the") || name.endsWith(",the") || 3397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", an") || name.endsWith(",an") || 3398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", a") || name.endsWith(",a")) { 3399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String fix = name.substring(1 + name.lastIndexOf(',')); 3400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = fix.trim() + " " + name.substring(0, name.lastIndexOf(',')); 3401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // TODO: word-capitalize the resulting name 3404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return name; 3405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Looks up the database based on the given URI. 3410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The requested URI 3412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @returns the database for the given URI 3413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private DatabaseHelper getDatabaseForUri(Uri uri) { 3415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 3416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getPathSegments().size() > 1) { 3417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return mDatabases.get(uri.getPathSegments().get(0)); 3418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 3421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Attach the database for a volume (internal or external). 3425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already attached, otherwise 3426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * checks the volume ID and sets up the corresponding database. 3427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param volume to attach, either {@link #INTERNAL_VOLUME} or {@link #EXTERNAL_VOLUME}. 3429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the content URI of the attached volume. 3430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Uri attachVolume(String volume) { 3432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Process.supportsProcesses() && Binder.getCallingPid() != Process.myPid()) { 3433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 3434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 3435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 3438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mDatabases.get(volume) != null) { // Already attached 3439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 3440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper db; 3443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 3444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db = new DatabaseHelper(getContext(), INTERNAL_DATABASE_NAME, true); 3445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (EXTERNAL_VOLUME.equals(volume)) { 3446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path = Environment.getExternalStorageDirectory().getPath(); 3447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int volumeID = FileUtils.getFatVolumeId(path); 3448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, path + " volume ID: " + volumeID); 3449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // generate database name based on volume ID 3451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String dbName = "external-" + Integer.toHexString(volumeID) + ".db"; 3452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db = new DatabaseHelper(getContext(), dbName, false); 34530027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen mVolumeId = volumeID; 3454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException("There is no volume named " + volume); 3456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases.put(volume, db); 3459702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3460702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!db.mInternal) { 3461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // clean up stray album art files: delete every file not in the database 3462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File[] files = new File( 3463702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Environment.getExternalStorageDirectory(), 3464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ALBUM_THUMB_FOLDER).listFiles(); 3465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashSet<String> fileSet = new HashSet(); 3466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; files != null && i < files.length; i++) { 3467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.add(files[i].getPath()); 3468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, 3471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String[] { MediaStore.Audio.Albums.ALBUM_ART }, null, null, null); 3472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor != null && cursor.moveToNext()) { 3474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.remove(cursor.getString(0)); 3475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 3477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (cursor != null) cursor.close(); 3478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Iterator<String> iterator = fileSet.iterator(); 3481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (iterator.hasNext()) { 3482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String filename = iterator.next(); 3483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "deleting obsolete album art " + filename); 3484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new File(filename).delete(); 3485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Attached volume: " + volume); 3490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 3491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Detach the database for a volume (must be external). 3495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already detached, otherwise 3496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * closes the database and sends a notification to listeners. 3497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The content URI of the volume, as returned by {@link #attachVolume} 3499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void detachVolume(Uri uri) { 3501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Process.supportsProcesses() && Binder.getCallingPid() != Process.myPid()) { 3502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 3503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 3504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3506702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = uri.getPathSegments().get(0); 3507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 3508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Deleting the internal volume is not allowed"); 3510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (!EXTERNAL_VOLUME.equals(volume)) { 3511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException( 3512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "There is no volume named " + volume); 3513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 3516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = mDatabases.get(volume); 3517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) return; 3518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 3521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(database.getReadableDatabase().getPath()); 3522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(System.currentTimeMillis()); 3523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (SQLException e) { 3524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Can't touch database file", e); 3525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases.remove(volume); 3528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project database.close(); 3529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 3532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Detached volume: " + volume); 3533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static String TAG = "MediaProvider"; 3536ae62a1d602e7ed2e0e30e271bddbb27aa71469f6Christian Mehlmauer private static final boolean LOCAL_LOGV = false; 3537bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin private static final int DATABASE_VERSION = 96; 3538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String INTERNAL_DATABASE_NAME = "internal.db"; 3539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // maximum number of cached external databases to keep 3541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MAX_EXTERNAL_DATABASES = 3; 3542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Delete databases that have not been used in two months 3544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // 60 days in milliseconds (1000 * 60 * 60 * 24 * 60) 3545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final long OBSOLETE_DATABASE_DB = 5184000000L; 3546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private HashMap<String, DatabaseHelper> mDatabases; 3548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Handler mThumbHandler; 3550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // name of the volume currently being scanned by the media scanner (or null) 3552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mMediaScannerVolume; 3553702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 35540027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // current FAT volume ID 35550027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen private int mVolumeId; 35560027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 3557702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String INTERNAL_VOLUME = "internal"; 3558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String EXTERNAL_VOLUME = "external"; 3559268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen static final String ALBUM_THUMB_FOLDER = "Android/data/com.android.providers.media/albumthumbs"; 3560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // path for writing contents of in memory temp database 3562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mTempDatabasePath; 3563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 35641717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // WARNING: the values of IMAGES_MEDIA, AUDIO_MEDIA, and VIDEO_MEDIA and AUDIO_PLAYLISTS 35651717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // are stored in the "objects" table, so do not renumber them unless you also add 35661717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // a corresponding database upgrade step for it. 3567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA = 1; 3568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA_ID = 2; 3569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS = 3; 3570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS_ID = 4; 3571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA = 100; 3573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID = 101; 3574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES = 102; 3575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES_ID = 103; 3576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS = 104; 3577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS_ID = 105; 3578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES = 106; 3579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID = 107; 3580702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID_MEMBERS = 108; 3581702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID_MEMBERS_ID = 109; 3582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS = 110; 3583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID = 111; 3584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS = 112; 3585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS_ID = 113; 3586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS = 114; 3587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID = 115; 3588702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS = 116; 3589702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS_ID = 117; 3590702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID_ALBUMS = 118; 3591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART = 119; 3592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART_ID = 120; 359371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private static final int AUDIO_ALBUMART_FILE_ID = 121; 3594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA = 200; 3596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA_ID = 201; 3597b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS = 202; 3598b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS_ID = 203; 3599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3600702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES = 300; 3601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES_ID = 301; 3602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3603a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_LEGACY = 400; 3604a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_BASIC = 401; 3605a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_FANCY = 402; 3606702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3607702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MEDIA_SCANNER = 500; 3608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 36090027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen private static final int FS_ID = 600; 36100027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 3611b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood private static final int MTP_OBJECTS = 700; 3612b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood private static final int MTP_OBJECTS_ID = 701; 3613e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood private static final int MTP_OBJECT_REFERENCES = 702; 3614b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 3615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final UriMatcher URI_MATCHER = 3616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new UriMatcher(UriMatcher.NO_MATCH); 3617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3618b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] ID_PROJECTION = new String[] { 3619b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID 3620b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 3621b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] MIME_TYPE_PROJECTION = new String[] { 3623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns._ID, // 0 3624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.MIME_TYPE, // 1 3625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 3626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3627b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] READY_FLAG_PROJECTION = new String[] { 3628b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID, 3629b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns.DATA, 3630b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Images.Media.MINI_THUMB_MAGIC 3631b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 3632b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] EXTERNAL_DATABASE_TABLES = new String[] { 3634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "images", 3635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "thumbnails", 3636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_meta", 3637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artists", 3638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "albums", 3639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres", 3640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map", 3641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_playlists", 3642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_playlists_map", 3643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "video", 3644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 3645702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3646e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood private static final String OBJECT_REFERENCES_QUERY = 3647e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood "SELECT objects._id FROM objects, audio_playlists_map" 3648e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood + " WHERE audio_playlists_map." + Audio.Playlists.Members.PLAYLIST_ID + "=?" 3649e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood + " AND audio_playlists_map.audio_id = objects." + ObjectColumns.MEDIA_ID 3650e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood + " AND objects." + ObjectColumns.MEDIA_TABLE + "=" + AUDIO_MEDIA 3651e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood + " ORDER BY audio_playlists_map." + Audio.Playlists.Members.PLAY_ORDER; 3652e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 3653702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static 3654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 3655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media", IMAGES_MEDIA); 3656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media/#", IMAGES_MEDIA_ID); 3657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails", IMAGES_THUMBNAILS); 3658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails/#", IMAGES_THUMBNAILS_ID); 3659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media", AUDIO_MEDIA); 3661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#", AUDIO_MEDIA_ID); 3662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES); 3663702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres/#", AUDIO_MEDIA_ID_GENRES_ID); 3664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists", AUDIO_MEDIA_ID_PLAYLISTS); 3665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists/#", AUDIO_MEDIA_ID_PLAYLISTS_ID); 3666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres", AUDIO_GENRES); 3667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#", AUDIO_GENRES_ID); 3668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#/members", AUDIO_GENRES_ID_MEMBERS); 3669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#/members/#", AUDIO_GENRES_ID_MEMBERS_ID); 3670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists", AUDIO_PLAYLISTS); 3671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#", AUDIO_PLAYLISTS_ID); 3672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members", AUDIO_PLAYLISTS_ID_MEMBERS); 3673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members/#", AUDIO_PLAYLISTS_ID_MEMBERS_ID); 3674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists", AUDIO_ARTISTS); 3675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#", AUDIO_ARTISTS_ID); 3676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#/albums", AUDIO_ARTISTS_ID_ALBUMS); 3677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums", AUDIO_ALBUMS); 3678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums/#", AUDIO_ALBUMS_ID); 3679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart", AUDIO_ALBUMART); 3680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart/#", AUDIO_ALBUMART_ID); 368171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen URI_MATCHER.addURI("media", "*/audio/media/#/albumart", AUDIO_ALBUMART_FILE_ID); 3682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media", VIDEO_MEDIA); 3684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media/#", VIDEO_MEDIA_ID); 3685b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails", VIDEO_THUMBNAILS); 3686b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails/#", VIDEO_THUMBNAILS_ID); 3687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/media_scanner", MEDIA_SCANNER); 3689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 36900027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen URI_MATCHER.addURI("media", "*/fs_id", FS_ID); 36910027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 3692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*", VOLUMES_ID); 3693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", null, VOLUMES); 3694702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3695b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // Used by MTP implementation 3696b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood URI_MATCHER.addURI("media", "*/object", MTP_OBJECTS); 3697b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood URI_MATCHER.addURI("media", "*/object/#", MTP_OBJECTS_ID); 3698e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood URI_MATCHER.addURI("media", "*/object/#/references", MTP_OBJECT_REFERENCES); 3699b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 3700a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen /** 3701a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen * @deprecated use the 'basic' or 'fancy' search Uris instead 3702a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen */ 3703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY, 3704a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 3705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 3706a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 3707a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 3708a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used for search suggestions 3709a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY, 3710a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_BASIC); 3711a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY + 3712a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "/*", AUDIO_SEARCH_BASIC); 3713a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 3714a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used by the music app's search activity 3715a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy", AUDIO_SEARCH_FANCY); 3716a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy/*", AUDIO_SEARCH_FANCY); 3717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project} 3719